diff --git a/ExternalLibraries/TemplateMatchLib.dll b/ExternalLibraries/TemplateMatchLib.dll new file mode 100644 index 0000000..e5b214e Binary files /dev/null and b/ExternalLibraries/TemplateMatchLib.dll differ diff --git a/ExternalLibraries/opencv_world455.dll b/ExternalLibraries/opencv_world455.dll new file mode 100644 index 0000000..2861ef5 Binary files /dev/null and b/ExternalLibraries/opencv_world455.dll differ diff --git a/ExternalLibraries/opencv_world455d.dll b/ExternalLibraries/opencv_world455d.dll new file mode 100644 index 0000000..fae5344 Binary files /dev/null and b/ExternalLibraries/opencv_world455d.dll differ diff --git a/ReleaseFiles/App.config b/ReleaseFiles/App.config index 7465d52..7123378 100644 --- a/ReleaseFiles/App.config +++ b/ReleaseFiles/App.config @@ -7,7 +7,10 @@ - + + + + @@ -122,7 +125,6 @@ - @@ -148,7 +150,7 @@ - + @@ -161,6 +163,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ReleaseFiles/BouncyCastle.Cryptography.dll b/ReleaseFiles/BouncyCastle.Cryptography.dll new file mode 100644 index 0000000..637242d Binary files /dev/null and b/ReleaseFiles/BouncyCastle.Cryptography.dll differ diff --git a/ReleaseFiles/Microsoft.DotNet.PlatformAbstractions.dll b/ReleaseFiles/Microsoft.DotNet.PlatformAbstractions.dll new file mode 100644 index 0000000..ae549ea Binary files /dev/null and b/ReleaseFiles/Microsoft.DotNet.PlatformAbstractions.dll differ diff --git a/ReleaseFiles/Microsoft.Extensions.DependencyInjection.dll b/ReleaseFiles/Microsoft.Extensions.DependencyInjection.dll index 3ebfa64..1034ee6 100644 Binary files a/ReleaseFiles/Microsoft.Extensions.DependencyInjection.dll and b/ReleaseFiles/Microsoft.Extensions.DependencyInjection.dll differ diff --git a/ReleaseFiles/Microsoft.Extensions.Logging.Abstractions.dll b/ReleaseFiles/Microsoft.Extensions.Logging.Abstractions.dll index 5bc5d39..2c87f79 100644 Binary files a/ReleaseFiles/Microsoft.Extensions.Logging.Abstractions.dll and b/ReleaseFiles/Microsoft.Extensions.Logging.Abstractions.dll differ diff --git a/ReleaseFiles/Microsoft.Extensions.Logging.dll b/ReleaseFiles/Microsoft.Extensions.Logging.dll index bda07c2..6df35e1 100644 Binary files a/ReleaseFiles/Microsoft.Extensions.Logging.dll and b/ReleaseFiles/Microsoft.Extensions.Logging.dll differ diff --git a/ReleaseFiles/Microsoft.Extensions.Options.dll b/ReleaseFiles/Microsoft.Extensions.Options.dll index 088358a..8a2a8c8 100644 Binary files a/ReleaseFiles/Microsoft.Extensions.Options.dll and b/ReleaseFiles/Microsoft.Extensions.Options.dll differ diff --git a/ReleaseFiles/Microsoft.Win32.SystemEvents.dll b/ReleaseFiles/Microsoft.Win32.SystemEvents.dll index 279431a..cd1f3d1 100644 Binary files a/ReleaseFiles/Microsoft.Win32.SystemEvents.dll and b/ReleaseFiles/Microsoft.Win32.SystemEvents.dll differ diff --git a/ReleaseFiles/PlcAddrDfn.xml b/ReleaseFiles/PlcAddrDfn.xml new file mode 100644 index 0000000..ed5dbb3 --- /dev/null +++ b/ReleaseFiles/PlcAddrDfn.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ReleaseFiles/System.Data.OleDb.dll b/ReleaseFiles/System.Data.OleDb.dll index f7840cd..95d3e71 100644 Binary files a/ReleaseFiles/System.Data.OleDb.dll and b/ReleaseFiles/System.Data.OleDb.dll differ diff --git a/ReleaseFiles/System.Data.SqlClient.dll b/ReleaseFiles/System.Data.SqlClient.dll index c9675bc..9d91846 100644 Binary files a/ReleaseFiles/System.Data.SqlClient.dll and b/ReleaseFiles/System.Data.SqlClient.dll differ diff --git a/ReleaseFiles/Templates/Logo.png b/ReleaseFiles/Templates/Logo.png new file mode 100644 index 0000000..5a4dc2c Binary files /dev/null and b/ReleaseFiles/Templates/Logo.png differ diff --git a/ReleaseFiles/Templates/Logo2.png b/ReleaseFiles/Templates/Logo2.png new file mode 100644 index 0000000..9674cea Binary files /dev/null and b/ReleaseFiles/Templates/Logo2.png differ diff --git a/ReleaseFiles/Templates/StandardReportTemplate.json b/ReleaseFiles/Templates/StandardReportTemplate.json new file mode 100644 index 0000000..64fb759 --- /dev/null +++ b/ReleaseFiles/Templates/StandardReportTemplate.json @@ -0,0 +1,222 @@ +{ + "document": { + "pageSize": "A4", + "orientation": "Portrait", + "margins": { "top": 40, "bottom": 20, "left": 20, "right": 20 }, + "header": { + "enabled": true, + "left": [ + "${loc:Report_Title}", + "${loc:Report_Id}:${metadata.reportId} | ${loc:Report_Date}:${formatDate(metadata.inspectionDate)} | ${loc:Report_Sample}:${metadata.sampleName}" + ], + "rightImageKey": "companyLogo", + "fontSize": 7, + "color": "#666666", + "showLine": true + }, + "footer": { + "enabled": true, + "left": ["${CompanyName}"], + "right": ["{currentPage} / {totalPages}"], + "fontSize": 8, + "color": "#666666", + "showLine": true + } + }, + "pages": [ + { + "type": "homepage", + "elements": [ + { + "type": "row", "size": [170, 40], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "companyLogo", "size": [50, 30], "align": "left" }, + { "type": "text", "content": "${CompanyName}", "style": "companyName", "align": "left" } + ] + }, + { + "type": "column", "align": "right", + "children": [ + { "type": "image", "dataKey": "softwareLogo", "size": [15, 20], "align": "right" }, + { "type": "text", "content": "${SoftwareName}", "style": "companyName", "align": "right" } + ] + } + ] + }, + { "type": "spacer", "size": [170, 15], "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Title}", "style": "title", "positioning": "flow" }, + { "type": "spacer", "size": [170, 10], "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Id}:${metadata.reportId}", "style": "homepageInfo", "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Sample}:${metadata.sampleName}", "style": "homepageInfo", "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Description}:${metadata.description}", "style": "homepageInfo", "positioning": "flow" }, + { "type": "image", "dataKey": "workpieceImage", "size": [160, 110], "border": true, "align": "center", "style": "imageDefault", "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Operator}:${metadata.operatorName}", "style": "homepageFooter", "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Date}:${formatDate(metadata.inspectionDate)}", "style": "homepageFooter", "positioning": "flow" } + ] + }, + { + "type": "summary", + "elements": [ + { "type": "text", "content": "${loc:Report_Summary}", "style": "homepageHeading", "positioning": "flow" }, + { + "type": "table", "dataKey": "summaryTable", "positioning": "flow", "size": [170, 0], "style": "tableDefault", + "columns": [ + { "header": "${loc:Field_InspectionType}", "field": "inspectionType", "width": 50, "align": "left" }, + { "header": "${loc:Field_Result}", "field": "classification", "width": 30, "align": "center", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } }, + { "header": "${loc:Field_Status}", "field": "status", "width": 30, "align": "center", "colorRules": { "合格": "#008000", "PASS": "#008000", "不合格": "#FF0000", "FAIL": "#FF0000" } } + ] + } + ] + }, + { + "type": "metricData", + "elements": [ + { "type": "text", "content": "${loc:Page_MetricData}", "style": "heading", "positioning": "flow" }, + { + "type": "row", "size": [170, 100], "widths": [6, 4], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "lineMeasurementImage", "size": [110, 90], "border": true, "align": "left" } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "${loc:Measurement_Type}:${measurementType}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Field_Point1}:${point1}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Field_Point2}:${point2}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_Distance}:${actualDistance} ${unit}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_Angle}:${angle}°", "style": "body", "align": "left" } + ] + } + ] + } + ] + }, + { + "type": "bgaInspection", + "elements": [ + { "type": "text", "content": "${loc:Page_BgaInspection}", "style": "heading", "positioning": "flow" }, + { + "type": "row", "size": [170, 100], "widths": [6, 4], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "bgaInspectionImage", "size": [110, 90], "border": true, "align": "left" } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "${loc:Bga_Count}:${bgaCount}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_VoidRate}:${formatPercent(voidRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_FillRate}:${formatPercent(fillRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Bga_TotalArea}:${formatNumber(totalBgaArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Bga_TotalVoidArea}:${formatNumber(totalVoidArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Bga_VoidLimit}:${formatPercent(voidLimit)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Table_Classification}:${classification}", "style": "conclusion", "align": "left", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } } + ] + } + ] + }, + { + "type": "table", "dataKey": "bgaBallsTable", "positioning": "flow", "size": [170, 0], "style": "tableDefault", + "columns": [ + { "header": "${loc:Bga_BallIndex}", "field": "index", "width": 25, "align": "center" }, + { "header": "${loc:Table_VoidRate}", "field": "voidRate", "width": 40, "align": "center" }, + { "header": "${loc:Table_Area}", "field": "area", "width": 40, "align": "center" }, + { "header": "${loc:Table_Classification}", "field": "classification", "width": 35, "align": "center", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } } + ] + } + ] + }, + { + "type": "voidInspection", + "elements": [ + { "type": "text", "content": "${loc:Page_VoidInspection}", "style": "heading", "positioning": "flow" }, + { + "type": "row", "size": [170, 100], "widths": [6, 4], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "voidInspectionImage", "size": [110, 90], "border": true, "align": "left" } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "${loc:Void_RoiArea}:${formatNumber(roiArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Void_TotalArea}:${formatNumber(totalVoidArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_VoidRate}:${formatPercent(voidRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Void_Limit}:${formatPercent(voidLimit)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Void_Count}:${voidCount}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Void_MaxArea}:${formatNumber(maxVoidArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Table_Classification}:${classification}", "style": "conclusion", "align": "left", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } } + ] + } + ] + }, + { + "type": "table", "dataKey": "voidsTable", "positioning": "flow", "size": [170, 0], "style": "tableDefault", + "columns": [ + { "header": "${loc:Table_Index}", "field": "index", "width": 20, "align": "center" }, + { "header": "${loc:Table_Area}", "field": "area", "width": 35, "align": "center" }, + { "header": "${loc:Table_AreaPercent}", "field": "areaPercent", "width": 35, "align": "center" }, + { "header": "${loc:Table_CenterX}", "field": "centerX", "width": 30, "align": "center" }, + { "header": "${loc:Table_CenterY}", "field": "centerY", "width": 30, "align": "center" } + ] + } + ] + }, + { + "type": "viaFillInspection", + "elements": [ + { "type": "text", "content": "${loc:Page_ViaFillInspection}", "style": "heading", "positioning": "flow" }, + { + "type": "row", "size": [170, 100], "widths": [6, 4], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "viaFillImage", "size": [110, 90], "border": true, "align": "left" } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "${loc:Fill_Rate}:${formatPercent(fillRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_VoidRate}:${formatPercent(voidRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Fill_FullDistance}:${formatNumber(fullDistance, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Fill_FillDistance}:${formatNumber(fillDistance, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Fill_THTLimit}:${formatPercent(thtLimit)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Table_Classification}:${classification}", "style": "conclusion", "align": "left", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } } + ] + } + ] + } + ] + } + ], + "styles": { + "title": { "font": "auto", "size": 28, "bold": true, "italic": false, "color": "#1a1a1a", "align": "center" }, + "companyName": { "font": "auto", "size": 10, "bold": false, "italic": false, "color": "#333333", "align": "center" }, + "homepageInfo": { "font": "auto", "size": 12, "bold": false, "italic": false, "color": "#333333", "align": "left", "paddingLeft": 10 }, + "homepageFooter": { "font": "auto", "size": 12, "bold": false, "italic": false, "color": "#333333", "align": "center" }, + "homepageHeading": { "font": "auto", "size": 14, "bold": true, "italic": false, "color": "#333333", "align": "left" }, + "heading": { "font": "auto", "size": 16, "bold": true, "italic": false, "color": "#333333", "align": "left", "marginBottom": 3 }, + "body": { "font": "auto", "size": 11, "bold": false, "italic": false, "color": "#333333", "align": "left" }, + "bodyBold": { "font": "auto", "size": 11, "bold": true, "italic": false, "color": "#1a1a1a", "align": "left" }, + "conclusion": { "font": "auto", "size": 12, "bold": true, "italic": false, "color": "#333333", "align": "left", "marginTop": 3 }, + "imageDefault": { "font": "auto", "size": 12, "bold": false, "italic": false, "color": "#333333", "align": "center", "marginTop": 5, "marginBottom": 5 }, + "tableHeader": { "font": "auto", "size": 10, "bold": true, "italic": false, "color": "#ffffff", "align": "center", "backgroundColor": "#4472C4" }, + "tableDefault": { "font": "auto", "size": 10, "bold": false, "italic": false, "color": "#333333", "align": "center", "marginTop": 5 }, + "tableCell": { "font": "auto", "size": 10, "bold": false, "italic": false, "color": "#333333", "align": "center" } + } +} diff --git a/ReleaseFiles/UserManual.pdf b/ReleaseFiles/UserManual.pdf new file mode 100644 index 0000000..2e0b69a Binary files /dev/null and b/ReleaseFiles/UserManual.pdf differ diff --git a/ReleaseFiles/XP.Camera.dll b/ReleaseFiles/XP.Camera.dll index 5a53c26..c927ba4 100644 Binary files a/ReleaseFiles/XP.Camera.dll and b/ReleaseFiles/XP.Camera.dll differ diff --git a/ReleaseFiles/XP.Camera.pdb b/ReleaseFiles/XP.Camera.pdb index 6112b4e..728c2e3 100644 Binary files a/ReleaseFiles/XP.Camera.pdb and b/ReleaseFiles/XP.Camera.pdb differ diff --git a/ReleaseFiles/XP.Common.dll b/ReleaseFiles/XP.Common.dll index 7bc5736..a8833d8 100644 Binary files a/ReleaseFiles/XP.Common.dll and b/ReleaseFiles/XP.Common.dll differ diff --git a/ReleaseFiles/XP.Common.pdb b/ReleaseFiles/XP.Common.pdb index 85e8f2e..c0fc2a9 100644 Binary files a/ReleaseFiles/XP.Common.pdb and b/ReleaseFiles/XP.Common.pdb differ diff --git a/ReleaseFiles/XP.Hardware.Detector.dll b/ReleaseFiles/XP.Hardware.Detector.dll index f02c874..9d8a578 100644 Binary files a/ReleaseFiles/XP.Hardware.Detector.dll and b/ReleaseFiles/XP.Hardware.Detector.dll differ diff --git a/ReleaseFiles/XP.Hardware.Detector.pdb b/ReleaseFiles/XP.Hardware.Detector.pdb index 436b074..6b4aa4e 100644 Binary files a/ReleaseFiles/XP.Hardware.Detector.pdb and b/ReleaseFiles/XP.Hardware.Detector.pdb differ diff --git a/ReleaseFiles/XP.Hardware.MotionControl.dll b/ReleaseFiles/XP.Hardware.MotionControl.dll index 2985310..d44058d 100644 Binary files a/ReleaseFiles/XP.Hardware.MotionControl.dll and b/ReleaseFiles/XP.Hardware.MotionControl.dll differ diff --git a/ReleaseFiles/XP.Hardware.MotionControl.pdb b/ReleaseFiles/XP.Hardware.MotionControl.pdb index 104cb14..8f0de88 100644 Binary files a/ReleaseFiles/XP.Hardware.MotionControl.pdb and b/ReleaseFiles/XP.Hardware.MotionControl.pdb differ diff --git a/ReleaseFiles/XP.Hardware.PLC.dll b/ReleaseFiles/XP.Hardware.PLC.dll index 9d3bdcc..6f3d513 100644 Binary files a/ReleaseFiles/XP.Hardware.PLC.dll and b/ReleaseFiles/XP.Hardware.PLC.dll differ diff --git a/ReleaseFiles/XP.Hardware.PLC.pdb b/ReleaseFiles/XP.Hardware.PLC.pdb index 80e5165..4c2e8ae 100644 Binary files a/ReleaseFiles/XP.Hardware.PLC.pdb and b/ReleaseFiles/XP.Hardware.PLC.pdb differ diff --git a/ReleaseFiles/XP.Hardware.RaySource.Comet.Messages.dll b/ReleaseFiles/XP.Hardware.RaySource.Comet.Messages.dll index e542b84..24b0107 100644 Binary files a/ReleaseFiles/XP.Hardware.RaySource.Comet.Messages.dll and b/ReleaseFiles/XP.Hardware.RaySource.Comet.Messages.dll differ diff --git a/ReleaseFiles/XP.Hardware.RaySource.Comet.Messages.pdb b/ReleaseFiles/XP.Hardware.RaySource.Comet.Messages.pdb index f393a13..7fe6daf 100644 Binary files a/ReleaseFiles/XP.Hardware.RaySource.Comet.Messages.pdb and b/ReleaseFiles/XP.Hardware.RaySource.Comet.Messages.pdb differ diff --git a/ReleaseFiles/XP.Hardware.RaySource.dll b/ReleaseFiles/XP.Hardware.RaySource.dll index 40c575b..21e3295 100644 Binary files a/ReleaseFiles/XP.Hardware.RaySource.dll and b/ReleaseFiles/XP.Hardware.RaySource.dll differ diff --git a/ReleaseFiles/XP.Hardware.RaySource.pdb b/ReleaseFiles/XP.Hardware.RaySource.pdb index d1976de..6176218 100644 Binary files a/ReleaseFiles/XP.Hardware.RaySource.pdb and b/ReleaseFiles/XP.Hardware.RaySource.pdb differ diff --git a/ReleaseFiles/XP.ImageProcessing.CfgControl.dll b/ReleaseFiles/XP.ImageProcessing.CfgControl.dll index 5668ff5..5924248 100644 Binary files a/ReleaseFiles/XP.ImageProcessing.CfgControl.dll and b/ReleaseFiles/XP.ImageProcessing.CfgControl.dll differ diff --git a/ReleaseFiles/XP.ImageProcessing.CfgControl.pdb b/ReleaseFiles/XP.ImageProcessing.CfgControl.pdb index 2a6bfa6..9e87d84 100644 Binary files a/ReleaseFiles/XP.ImageProcessing.CfgControl.pdb and b/ReleaseFiles/XP.ImageProcessing.CfgControl.pdb differ diff --git a/ReleaseFiles/XP.ImageProcessing.Core.dll b/ReleaseFiles/XP.ImageProcessing.Core.dll index 80646aa..0af1c02 100644 Binary files a/ReleaseFiles/XP.ImageProcessing.Core.dll and b/ReleaseFiles/XP.ImageProcessing.Core.dll differ diff --git a/ReleaseFiles/XP.ImageProcessing.Core.pdb b/ReleaseFiles/XP.ImageProcessing.Core.pdb index 190e2af..3690f67 100644 Binary files a/ReleaseFiles/XP.ImageProcessing.Core.pdb and b/ReleaseFiles/XP.ImageProcessing.Core.pdb differ diff --git a/ReleaseFiles/XP.ImageProcessing.Processors.dll b/ReleaseFiles/XP.ImageProcessing.Processors.dll index c776aef..645297e 100644 Binary files a/ReleaseFiles/XP.ImageProcessing.Processors.dll and b/ReleaseFiles/XP.ImageProcessing.Processors.dll differ diff --git a/ReleaseFiles/XP.ImageProcessing.Processors.pdb b/ReleaseFiles/XP.ImageProcessing.Processors.pdb index 12ee5d7..7b55029 100644 Binary files a/ReleaseFiles/XP.ImageProcessing.Processors.pdb and b/ReleaseFiles/XP.ImageProcessing.Processors.pdb differ diff --git a/ReleaseFiles/XP.ImageProcessing.RoiControl.dll b/ReleaseFiles/XP.ImageProcessing.RoiControl.dll index ad057b3..d478d53 100644 Binary files a/ReleaseFiles/XP.ImageProcessing.RoiControl.dll and b/ReleaseFiles/XP.ImageProcessing.RoiControl.dll differ diff --git a/ReleaseFiles/XP.ImageProcessing.RoiControl.pdb b/ReleaseFiles/XP.ImageProcessing.RoiControl.pdb index aaf84d2..5441b82 100644 Binary files a/ReleaseFiles/XP.ImageProcessing.RoiControl.pdb and b/ReleaseFiles/XP.ImageProcessing.RoiControl.pdb differ diff --git a/ReleaseFiles/XP.ReportEngine.dll b/ReleaseFiles/XP.ReportEngine.dll new file mode 100644 index 0000000..c3d733d Binary files /dev/null and b/ReleaseFiles/XP.ReportEngine.dll differ diff --git a/ReleaseFiles/XP.ReportEngine.pdb b/ReleaseFiles/XP.ReportEngine.pdb new file mode 100644 index 0000000..ffd6093 Binary files /dev/null and b/ReleaseFiles/XP.ReportEngine.pdb differ diff --git a/ReleaseFiles/XplorePlane.deps.json b/ReleaseFiles/XplorePlane.deps.json index 6d5820f..7583502 100644 --- a/ReleaseFiles/XplorePlane.deps.json +++ b/ReleaseFiles/XplorePlane.deps.json @@ -1,11 +1,12 @@ { "runtimeTarget": { - "name": ".NETCoreApp,Version=v8.0", + "name": ".NETCoreApp,Version=v8.0/win-x64", "signature": "" }, "compilationOptions": {}, "targets": { - ".NETCoreApp,Version=v8.0": { + ".NETCoreApp,Version=v8.0": {}, + ".NETCoreApp,Version=v8.0/win-x64": { "XplorePlane/1.0.0": { "dependencies": { "Emgu.CV": "4.10.0.5680", @@ -29,12 +30,21 @@ "XP.ImageProcessing.Core": "1.0.0", "XP.ImageProcessing.Processors": "1.0.0", "XP.ImageProcessing.RoiControl": "1.0.0", + "XP.ReportEngine": "1.0.0", "BR.AN.PviServices": "1.1.0.0" }, "runtime": { "XplorePlane.dll": {} } }, + "BouncyCastle.Cryptography/2.2.1": { + "runtime": { + "lib/net6.0/BouncyCastle.Cryptography.dll": { + "assemblyVersion": "2.0.0.0", + "fileVersion": "2.2.1.47552" + } + } + }, "ControlzEx/5.0.1": { "dependencies": { "Microsoft.Xaml.Behaviors.Wpf": "1.1.122", @@ -88,171 +98,48 @@ "Emgu.runtime.windows.msvc.rt.x64": "19.42.34435", "Emgu.runtime.windows.msvc.rt.x86": "19.42.34435" }, - "runtimeTargets": { - "runtimes/win-arm64/native/cvextern.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "4.10.0.5680" - }, + "native": { "runtimes/win-x64/native/cvextern.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "4.10.0.5680" }, "runtimes/win-x64/native/libusb-1.0.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "0.0.0.0" }, "runtimes/win-x64/native/opencv_videoio_ffmpeg4100_64.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "2024.5.0.0" - }, - "runtimes/win-x86/native/cvextern.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "4.10.0.5680" - }, - "runtimes/win-x86/native/libusb-1.0.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x86/native/opencv_videoio_ffmpeg4100.dll": { - "rid": "win-x86", - "assetType": "native", "fileVersion": "2024.5.0.0" } } }, - "Emgu.runtime.windows.msvc.rt.arm64/19.42.34435": { - "runtimeTargets": { - "runtimes/win-arm64/native/concrt140.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-arm64/native/msvcp140.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-arm64/native/msvcp140_1.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-arm64/native/msvcp140_2.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-arm64/native/msvcp140_atomic_wait.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-arm64/native/msvcp140_codecvt_ids.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-arm64/native/vcruntime140.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-arm64/native/vcruntime140_1.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - } - } - }, + "Emgu.runtime.windows.msvc.rt.arm64/19.42.34435": {}, "Emgu.runtime.windows.msvc.rt.x64/19.42.34435": { - "runtimeTargets": { + "native": { "runtimes/win-x64/native/concrt140.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "14.42.34433.0" }, "runtimes/win-x64/native/msvcp140.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "14.42.34433.0" }, "runtimes/win-x64/native/msvcp140_1.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "14.42.34433.0" }, "runtimes/win-x64/native/msvcp140_2.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "14.42.34433.0" }, "runtimes/win-x64/native/msvcp140_atomic_wait.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "14.42.34433.0" }, "runtimes/win-x64/native/msvcp140_codecvt_ids.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "14.42.34433.0" }, "runtimes/win-x64/native/vcruntime140.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "14.42.34433.0" }, "runtimes/win-x64/native/vcruntime140_1.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "14.42.34433.0" - } - } - }, - "Emgu.runtime.windows.msvc.rt.x86/19.42.34435": { - "runtimeTargets": { - "runtimes/win-x86/native/concrt140.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-x86/native/msvcp140.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-x86/native/msvcp140_1.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-x86/native/msvcp140_2.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-x86/native/msvcp140_atomic_wait.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-x86/native/msvcp140_codecvt_ids.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "14.42.34433.0" - }, - "runtimes/win-x86/native/vcruntime140.dll": { - "rid": "win-x86", - "assetType": "native", "fileVersion": "14.42.34433.0" } } }, + "Emgu.runtime.windows.msvc.rt.x86/19.42.34435": {}, "EntityFramework/6.4.4": { "dependencies": { "Microsoft.CSharp": "4.7.0", @@ -283,546 +170,103 @@ } } }, - "MahApps.Metro/2.4.11": { + "itext/8.0.5": { "dependencies": { - "ControlzEx": "5.0.1" + "Microsoft.DotNet.PlatformAbstractions": "1.1.0", + "Microsoft.Extensions.DependencyModel": "10.0.0", + "Microsoft.Extensions.Logging": "5.0.0", + "System.Collections.NonGeneric": "4.3.0", + "System.Diagnostics.Process": "4.3.0", + "System.Globalization.Extensions": "4.3.0", + "System.Runtime.Loader": "4.3.0", + "System.Runtime.Serialization.Formatters": "4.3.0", + "System.Security.Cryptography.Csp": "4.3.0", + "System.Text.Encoding.CodePages": "4.3.0", + "System.Text.RegularExpressions": "4.3.1", + "System.Threading.Thread": "4.3.0", + "System.Threading.ThreadPool": "4.3.0", + "System.Xml.XmlDocument": "4.3.0", + "itext.commons": "8.0.5" }, "runtime": { - "lib/netcoreapp3.1/MahApps.Metro.dll": { - "assemblyVersion": "2.0.0.0", - "fileVersion": "2.4.11.0" - } - }, - "resources": { - "lib/netcoreapp3.1/de/MahApps.Metro.resources.dll": { - "locale": "de" + "lib/netstandard2.0/itext.barcodes.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.bouncy-castle-connector.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.forms.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.io.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.kernel.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.layout.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.pdfa.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.pdfua.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.sign.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.styledxmlparser.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" + }, + "lib/netstandard2.0/itext.svg.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" } } }, - "MahApps.Metro.IconPacks/6.2.1": { + "itext.bouncy-castle-adapter/8.0.5": { "dependencies": { - "MahApps.Metro.IconPacks.BootstrapIcons": "6.2.1", - "MahApps.Metro.IconPacks.BoxIcons": "6.2.1", - "MahApps.Metro.IconPacks.BoxIcons2": "6.2.1", - "MahApps.Metro.IconPacks.CircumIcons": "6.2.1", - "MahApps.Metro.IconPacks.Codicons": "6.2.1", - "MahApps.Metro.IconPacks.Coolicons": "6.2.1", - "MahApps.Metro.IconPacks.Core": "6.2.1", - "MahApps.Metro.IconPacks.Entypo": "6.2.1", - "MahApps.Metro.IconPacks.EvaIcons": "6.2.1", - "MahApps.Metro.IconPacks.FeatherIcons": "6.2.1", - "MahApps.Metro.IconPacks.FileIcons": "6.2.1", - "MahApps.Metro.IconPacks.FontAwesome": "6.2.1", - "MahApps.Metro.IconPacks.FontAwesome5": "6.2.1", - "MahApps.Metro.IconPacks.FontAwesome6": "6.2.1", - "MahApps.Metro.IconPacks.Fontaudio": "6.2.1", - "MahApps.Metro.IconPacks.Fontisto": "6.2.1", - "MahApps.Metro.IconPacks.ForkAwesome": "6.2.1", - "MahApps.Metro.IconPacks.GameIcons": "6.2.1", - "MahApps.Metro.IconPacks.Ionicons": "6.2.1", - "MahApps.Metro.IconPacks.JamIcons": "6.2.1", - "MahApps.Metro.IconPacks.KeyruneIcons": "6.2.1", - "MahApps.Metro.IconPacks.Lucide": "6.2.1", - "MahApps.Metro.IconPacks.Material": "6.2.1", - "MahApps.Metro.IconPacks.MaterialDesign": "6.2.1", - "MahApps.Metro.IconPacks.MaterialLight": "6.2.1", - "MahApps.Metro.IconPacks.MemoryIcons": "6.2.1", - "MahApps.Metro.IconPacks.Microns": "6.2.1", - "MahApps.Metro.IconPacks.MingCuteIcons": "6.2.1", - "MahApps.Metro.IconPacks.Modern": "6.2.1", - "MahApps.Metro.IconPacks.MynaUIIcons": "6.2.1", - "MahApps.Metro.IconPacks.Octicons": "6.2.1", - "MahApps.Metro.IconPacks.PhosphorIcons": "6.2.1", - "MahApps.Metro.IconPacks.PicolIcons": "6.2.1", - "MahApps.Metro.IconPacks.PixelartIcons": "6.2.1", - "MahApps.Metro.IconPacks.RPGAwesome": "6.2.1", - "MahApps.Metro.IconPacks.RadixIcons": "6.2.1", - "MahApps.Metro.IconPacks.RemixIcon": "6.2.1", - "MahApps.Metro.IconPacks.SimpleIcons": "6.2.1", - "MahApps.Metro.IconPacks.Typicons": "6.2.1", - "MahApps.Metro.IconPacks.Unicons": "6.2.1", - "MahApps.Metro.IconPacks.VaadinIcons": "6.2.1", - "MahApps.Metro.IconPacks.WeatherIcons": "6.2.1", - "MahApps.Metro.IconPacks.Zondicons": "6.2.1" + "BouncyCastle.Cryptography": "2.2.1", + "itext.commons": "8.0.5" }, "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" + "lib/netstandard2.0/itext.bouncy-castle-adapter.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" } } }, - "MahApps.Metro.IconPacks.BootstrapIcons/6.2.1": { + "itext.commons/8.0.5": { "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" + "Microsoft.Extensions.Logging": "5.0.0", + "Newtonsoft.Json": "13.0.3" }, "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.BootstrapIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" + "lib/netstandard2.0/itext.commons.dll": { + "assemblyVersion": "8.0.5.0", + "fileVersion": "8.0.5.0" } } }, - "MahApps.Metro.IconPacks.BoxIcons/6.2.1": { + "itext7/8.0.5": { "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.BoxIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } + "itext": "8.0.5" } }, - "MahApps.Metro.IconPacks.BoxIcons2/6.2.1": { + "itext7.bouncy-castle-adapter/8.0.5": { "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.BoxIcons2.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.CircumIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.CircumIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Codicons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Codicons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Coolicons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Coolicons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Core/6.2.1": { - "dependencies": { - "System.Text.Json": "10.0.0" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Core.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Entypo/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Entypo.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.EvaIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.EvaIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.FeatherIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.FeatherIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.FileIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.FileIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Fontaudio/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Fontaudio.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.FontAwesome/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.FontAwesome.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.FontAwesome5/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.FontAwesome5.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.FontAwesome6/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.FontAwesome6.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Fontisto/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Fontisto.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.ForkAwesome/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.ForkAwesome.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.GameIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.GameIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Ionicons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Ionicons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.JamIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.JamIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.KeyruneIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.KeyruneIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Lucide/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Lucide.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Material/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Material.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.MaterialDesign/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.MaterialDesign.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.MaterialLight/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.MaterialLight.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.MemoryIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.MemoryIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Microns/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Microns.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.MingCuteIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.MingCuteIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Modern/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Modern.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.MynaUIIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.MynaUIIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Octicons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Octicons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.PhosphorIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.PhosphorIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.PicolIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.PicolIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.PixelartIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.PixelartIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.RadixIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.RadixIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.RemixIcon/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.RemixIcon.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.RPGAwesome/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.RPGAwesome.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.SimpleIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.SimpleIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Typicons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Typicons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Unicons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Unicons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.VaadinIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.VaadinIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.WeatherIcons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.WeatherIcons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } - } - }, - "MahApps.Metro.IconPacks.Zondicons/6.2.1": { - "dependencies": { - "MahApps.Metro.IconPacks.Core": "6.2.1" - }, - "runtime": { - "lib/net8.0-windows7.0/MahApps.Metro.IconPacks.Zondicons.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.2.1.0" - } + "itext.bouncy-castle-adapter": "8.0.5" } }, "Microsoft.Bcl.AsyncInterfaces/1.1.1": { @@ -860,6 +304,24 @@ } } }, + "Microsoft.DotNet.PlatformAbstractions/1.1.0": { + "dependencies": { + "System.AppContext": "4.3.0", + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.InteropServices.RuntimeInformation": "4.3.0" + }, + "runtime": { + "lib/netstandard1.3/Microsoft.DotNet.PlatformAbstractions.dll": { + "assemblyVersion": "1.1.0.0", + "fileVersion": "1.1.0.0" + } + } + }, "Microsoft.EntityFrameworkCore/3.1.5": { "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "1.1.1", @@ -867,8 +329,8 @@ "Microsoft.EntityFrameworkCore.Abstractions": "3.1.5", "Microsoft.EntityFrameworkCore.Analyzers": "3.1.5", "Microsoft.Extensions.Caching.Memory": "3.1.5", - "Microsoft.Extensions.DependencyInjection": "3.1.5", - "Microsoft.Extensions.Logging": "3.1.5", + "Microsoft.Extensions.DependencyInjection": "5.0.0", + "Microsoft.Extensions.Logging": "5.0.0", "System.Collections.Immutable": "1.7.1", "System.ComponentModel.Annotations": "4.7.0", "System.Diagnostics.DiagnosticSource": "4.7.1" @@ -904,8 +366,8 @@ "dependencies": { "Microsoft.Extensions.Caching.Abstractions": "3.1.5", "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1", - "Microsoft.Extensions.Logging.Abstractions": "3.1.5", - "Microsoft.Extensions.Options": "3.1.5" + "Microsoft.Extensions.Logging.Abstractions": "5.0.0", + "Microsoft.Extensions.Options": "5.0.0" }, "runtime": { "lib/netcoreapp3.1/Microsoft.Extensions.Caching.Memory.dll": { @@ -949,14 +411,14 @@ } } }, - "Microsoft.Extensions.DependencyInjection/3.1.5": { + "Microsoft.Extensions.DependencyInjection/5.0.0": { "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1" }, "runtime": { - "lib/netcoreapp3.1/Microsoft.Extensions.DependencyInjection.dll": { - "assemblyVersion": "3.1.5.0", - "fileVersion": "3.100.520.27009" + "lib/net5.0/Microsoft.Extensions.DependencyInjection.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" } } }, @@ -980,37 +442,37 @@ } } }, - "Microsoft.Extensions.Logging/3.1.5": { + "Microsoft.Extensions.Logging/5.0.0": { "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "10.0.0", - "Microsoft.Extensions.DependencyInjection": "3.1.5", - "Microsoft.Extensions.Logging.Abstractions": "3.1.5", - "Microsoft.Extensions.Options": "3.1.5" + "Microsoft.Extensions.DependencyInjection": "5.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1", + "Microsoft.Extensions.Logging.Abstractions": "5.0.0", + "Microsoft.Extensions.Options": "5.0.0" }, "runtime": { - "lib/netcoreapp3.1/Microsoft.Extensions.Logging.dll": { - "assemblyVersion": "3.1.5.0", - "fileVersion": "3.100.520.27009" + "lib/netstandard2.1/Microsoft.Extensions.Logging.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" } } }, - "Microsoft.Extensions.Logging.Abstractions/3.1.5": { + "Microsoft.Extensions.Logging.Abstractions/5.0.0": { "runtime": { "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { - "assemblyVersion": "3.1.5.0", - "fileVersion": "3.100.520.27009" + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" } } }, - "Microsoft.Extensions.Options/3.1.5": { + "Microsoft.Extensions.Options/5.0.0": { "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1", "Microsoft.Extensions.Primitives": "10.0.0" }, "runtime": { - "lib/netcoreapp3.1/Microsoft.Extensions.Options.dll": { - "assemblyVersion": "3.1.5.0", - "fileVersion": "3.100.520.27009" + "lib/net5.0/Microsoft.Extensions.Options.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.20.51904" } } }, @@ -1032,75 +494,11 @@ "Microsoft.ML.OnnxRuntime.Gpu.Linux/1.20.1": { "dependencies": { "Microsoft.ML.OnnxRuntime.Managed": "1.20.1" - }, - "runtimeTargets": { - "runtimes/linux-x64/native/libonnxruntime.so": { - "rid": "linux-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-x64/native/libonnxruntime_providers_cuda.so": { - "rid": "linux-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-x64/native/libonnxruntime_providers_shared.so": { - "rid": "linux-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-x64/native/libonnxruntime_providers_tensorrt.so": { - "rid": "linux-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - } } }, "Microsoft.ML.OnnxRuntime.Gpu.Windows/1.20.1": { "dependencies": { "Microsoft.ML.OnnxRuntime.Managed": "1.20.1" - }, - "runtimeTargets": { - "runtimes/win-x64/native/onnxruntime.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "1.20.24.1119" - }, - "runtimes/win-x64/native/onnxruntime.lib": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x64/native/onnxruntime_providers_cuda.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x64/native/onnxruntime_providers_cuda.lib": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x64/native/onnxruntime_providers_shared.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "1.20.24.1119" - }, - "runtimes/win-x64/native/onnxruntime_providers_shared.lib": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x64/native/onnxruntime_providers_tensorrt.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x64/native/onnxruntime_providers_tensorrt.lib": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - } } }, "Microsoft.ML.OnnxRuntime.Managed/1.20.1": { @@ -1162,7 +560,8 @@ "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.win.Microsoft.Win32.Primitives": "4.3.0" } }, "Microsoft.Win32.Registry/4.7.0": { @@ -1173,15 +572,7 @@ }, "Microsoft.Win32.SystemEvents/9.0.0": { "runtime": { - "lib/net8.0/Microsoft.Win32.SystemEvents.dll": { - "assemblyVersion": "9.0.0.0", - "fileVersion": "9.0.24.52809" - } - }, - "runtimeTargets": { "runtimes/win/lib/net8.0/Microsoft.Win32.SystemEvents.dll": { - "rid": "win", - "assetType": "runtime", "assemblyVersion": "9.0.0.0", "fileVersion": "9.0.24.52809" } @@ -1235,7 +626,7 @@ "System.Security.Cryptography.X509Certificates": "4.3.0", "System.Text.Encoding": "4.3.0", "System.Text.Encoding.Extensions": "4.3.0", - "System.Text.RegularExpressions": "4.3.0", + "System.Text.RegularExpressions": "4.3.1", "System.Threading": "4.3.0", "System.Threading.Tasks": "4.3.0", "System.Threading.Timer": "4.3.0", @@ -1318,6 +709,31 @@ } } }, + "runtime.any.System.Collections/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.1" + } + }, + "runtime.any.System.Diagnostics.Tools/4.3.0": {}, + "runtime.any.System.Diagnostics.Tracing/4.3.0": {}, + "runtime.any.System.Globalization/4.3.0": {}, + "runtime.any.System.Globalization.Calendars/4.3.0": {}, + "runtime.any.System.IO/4.3.0": {}, + "runtime.any.System.Reflection/4.3.0": {}, + "runtime.any.System.Reflection.Extensions/4.3.0": {}, + "runtime.any.System.Reflection.Primitives/4.3.0": {}, + "runtime.any.System.Resources.ResourceManager/4.3.0": {}, + "runtime.any.System.Runtime/4.3.0": { + "dependencies": { + "System.Private.Uri": "4.3.0" + } + }, + "runtime.any.System.Runtime.Handles/4.3.0": {}, + "runtime.any.System.Runtime.InteropServices/4.3.0": {}, + "runtime.any.System.Text.Encoding/4.3.0": {}, + "runtime.any.System.Text.Encoding.Extensions/4.3.0": {}, + "runtime.any.System.Threading.Tasks/4.3.0": {}, + "runtime.any.System.Threading.Timer/4.3.0": {}, "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, @@ -1373,31 +789,93 @@ "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, - "runtime.win-arm64.runtime.native.System.Data.SqlClient.sni/4.4.0": { - "runtimeTargets": { - "runtimes/win-arm64/native/sni.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "4.6.25512.1" - } - } - }, + "runtime.win-arm64.runtime.native.System.Data.SqlClient.sni/4.4.0": {}, "runtime.win-x64.runtime.native.System.Data.SqlClient.sni/4.4.0": { - "runtimeTargets": { + "native": { "runtimes/win-x64/native/sni.dll": { - "rid": "win-x64", - "assetType": "native", "fileVersion": "4.6.25512.1" } } }, - "runtime.win-x86.runtime.native.System.Data.SqlClient.sni/4.4.0": { - "runtimeTargets": { - "runtimes/win-x86/native/sni.dll": { - "rid": "win-x86", - "assetType": "native", - "fileVersion": "4.6.25512.1" - } + "runtime.win-x86.runtime.native.System.Data.SqlClient.sni/4.4.0": {}, + "runtime.win.Microsoft.Win32.Primitives/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.1", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "runtime.win.System.Console/4.3.1": { + "dependencies": { + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "runtime.win.System.Diagnostics.Debug/4.3.0": {}, + "runtime.win.System.IO.FileSystem/4.3.0": { + "dependencies": { + "System.Buffers": "4.3.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Overlapped": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "runtime.win.System.Net.Primitives/4.3.0": { + "dependencies": { + "Microsoft.Win32.Primitives": "4.3.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "runtime.win.System.Net.Sockets/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Net.NameResolution": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Principal.Windows": "4.7.0", + "System.Threading": "4.3.0", + "System.Threading.Overlapped": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "runtime.win.System.Runtime.Extensions/4.3.0": { + "dependencies": { + "System.Private.Uri": "4.3.0" } }, "Serilog/4.3.1": { @@ -1564,120 +1042,8 @@ } }, "SQLitePCLRaw.lib.e_sqlite3/2.1.11": { - "runtimeTargets": { - "runtimes/browser-wasm/nativeassets/net8.0/e_sqlite3.a": { - "rid": "browser-wasm", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-arm/native/libe_sqlite3.so": { - "rid": "linux-arm", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-arm64/native/libe_sqlite3.so": { - "rid": "linux-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-armel/native/libe_sqlite3.so": { - "rid": "linux-armel", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-mips64/native/libe_sqlite3.so": { - "rid": "linux-mips64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-musl-arm/native/libe_sqlite3.so": { - "rid": "linux-musl-arm", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-musl-arm64/native/libe_sqlite3.so": { - "rid": "linux-musl-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-musl-riscv64/native/libe_sqlite3.so": { - "rid": "linux-musl-riscv64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-musl-s390x/native/libe_sqlite3.so": { - "rid": "linux-musl-s390x", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-musl-x64/native/libe_sqlite3.so": { - "rid": "linux-musl-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-ppc64le/native/libe_sqlite3.so": { - "rid": "linux-ppc64le", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-riscv64/native/libe_sqlite3.so": { - "rid": "linux-riscv64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-s390x/native/libe_sqlite3.so": { - "rid": "linux-s390x", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-x64/native/libe_sqlite3.so": { - "rid": "linux-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/linux-x86/native/libe_sqlite3.so": { - "rid": "linux-x86", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/maccatalyst-arm64/native/libe_sqlite3.dylib": { - "rid": "maccatalyst-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/maccatalyst-x64/native/libe_sqlite3.dylib": { - "rid": "maccatalyst-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/osx-arm64/native/libe_sqlite3.dylib": { - "rid": "osx-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/osx-x64/native/libe_sqlite3.dylib": { - "rid": "osx-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-arm/native/e_sqlite3.dll": { - "rid": "win-arm", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-arm64/native/e_sqlite3.dll": { - "rid": "win-arm64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, + "native": { "runtimes/win-x64/native/e_sqlite3.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/win-x86/native/e_sqlite3.dll": { - "rid": "win-x86", - "assetType": "native", "fileVersion": "0.0.0.0" } } @@ -1700,25 +1066,8 @@ "fileVersion": "1.0.118.0" } }, - "runtimeTargets": { - "runtimes/linux-x64/native/SQLite.Interop.dll": { - "rid": "linux-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, - "runtimes/osx-x64/native/SQLite.Interop.dll": { - "rid": "osx-x64", - "assetType": "native", - "fileVersion": "0.0.0.0" - }, + "native": { "runtimes/win-x64/native/SQLite.Interop.dll": { - "rid": "win-x64", - "assetType": "native", - "fileVersion": "1.0.118.0" - }, - "runtimes/win-x86/native/SQLite.Interop.dll": { - "rid": "win-x86", - "assetType": "native", "fileVersion": "1.0.118.0" } } @@ -1742,7 +1091,8 @@ "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Collections": "4.3.0" } }, "System.Collections.Concurrent/4.3.0": { @@ -1760,17 +1110,21 @@ } }, "System.Collections.Immutable/1.7.1": {}, + "System.Collections.NonGeneric/4.3.0": { + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, "System.ComponentModel.Annotations/4.7.0": {}, "System.Configuration.ConfigurationManager/8.0.0": { "dependencies": { "System.Diagnostics.EventLog": "8.0.0", "System.Security.Cryptography.ProtectedData": "8.0.0" - }, - "runtime": { - "lib/net8.0/System.Configuration.ConfigurationManager.dll": { - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.23.53103" - } } }, "System.Console/4.3.0": { @@ -1779,7 +1133,8 @@ "Microsoft.NETCore.Targets": "1.1.3", "System.IO": "4.3.0", "System.Runtime": "4.3.1", - "System.Text.Encoding": "4.3.0" + "System.Text.Encoding": "4.3.0", + "runtime.win.System.Console": "4.3.1" } }, "System.Data.OleDb/6.0.0": { @@ -1788,15 +1143,7 @@ "System.Diagnostics.PerformanceCounter": "6.0.0" }, "runtime": { - "lib/net6.0/System.Data.OleDb.dll": { - "assemblyVersion": "6.0.0.0", - "fileVersion": "6.0.21.52210" - } - }, - "runtimeTargets": { "runtimes/win/lib/net6.0/System.Data.OleDb.dll": { - "rid": "win", - "assetType": "runtime", "assemblyVersion": "6.0.0.0", "fileVersion": "6.0.21.52210" } @@ -1809,21 +1156,7 @@ "runtime.native.System.Data.SqlClient.sni": "4.7.0" }, "runtime": { - "lib/netcoreapp2.1/System.Data.SqlClient.dll": { - "assemblyVersion": "4.6.1.1", - "fileVersion": "4.700.20.6702" - } - }, - "runtimeTargets": { - "runtimes/unix/lib/netcoreapp2.1/System.Data.SqlClient.dll": { - "rid": "unix", - "assetType": "runtime", - "assemblyVersion": "4.6.1.1", - "fileVersion": "4.700.20.6702" - }, "runtimes/win/lib/netcoreapp2.1/System.Data.SqlClient.dll": { - "rid": "win", - "assetType": "runtime", "assemblyVersion": "4.6.1.1", "fileVersion": "4.700.20.6702" } @@ -1855,43 +1188,56 @@ "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.win.System.Diagnostics.Debug": "4.3.0" } }, "System.Diagnostics.DiagnosticSource/4.7.1": {}, - "System.Diagnostics.EventLog/8.0.0": { - "runtime": { - "lib/net8.0/System.Diagnostics.EventLog.dll": { - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.23.53103" - } - }, - "runtimeTargets": { - "runtimes/win/lib/net8.0/System.Diagnostics.EventLog.dll": { - "rid": "win", - "assetType": "runtime", - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.23.53103" - } - } - }, + "System.Diagnostics.EventLog/8.0.0": {}, "System.Diagnostics.PerformanceCounter/6.0.0": { "dependencies": { "System.Configuration.ConfigurationManager": "8.0.0" } }, + "System.Diagnostics.Process/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.Win32.Primitives": "4.3.0", + "Microsoft.Win32.Registry": "4.7.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Thread": "4.3.0", + "System.Threading.ThreadPool": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, "System.Diagnostics.Tools/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Diagnostics.Tools": "4.3.0" } }, "System.Diagnostics.Tracing/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Diagnostics.Tracing": "4.3.0" } }, "System.Drawing.Common/9.0.0": { @@ -1919,7 +1265,8 @@ "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Globalization": "4.3.0" } }, "System.Globalization.Calendars/4.3.0": { @@ -1927,7 +1274,8 @@ "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", "System.Globalization": "4.3.0", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Globalization.Calendars": "4.3.0" } }, "System.Globalization.Extensions/4.3.0": { @@ -1946,7 +1294,8 @@ "Microsoft.NETCore.Targets": "1.1.3", "System.Runtime": "4.3.1", "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" + "System.Threading.Tasks": "4.3.0", + "runtime.any.System.IO": "4.3.0" } }, "System.IO.Compression/4.3.0": { @@ -1990,7 +1339,8 @@ "System.Runtime": "4.3.1", "System.Runtime.Handles": "4.3.0", "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" + "System.Threading.Tasks": "4.3.0", + "runtime.win.System.IO.FileSystem": "4.3.0" } }, "System.IO.FileSystem.Primitives/4.3.0": { @@ -2067,12 +1417,31 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, + "System.Net.NameResolution/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Principal.Windows": "4.7.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, "System.Net.Primitives/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", "System.Runtime": "4.3.1", - "System.Runtime.Handles": "4.3.0" + "System.Runtime.Handles": "4.3.0", + "runtime.win.System.Net.Primitives": "4.3.0" } }, "System.Net.Sockets/4.3.0": { @@ -2082,7 +1451,8 @@ "System.IO": "4.3.0", "System.Net.Primitives": "4.3.0", "System.Runtime": "4.3.1", - "System.Threading.Tasks": "4.3.0" + "System.Threading.Tasks": "4.3.0", + "runtime.win.System.Net.Sockets": "4.3.0" } }, "System.ObjectModel/4.3.0": { @@ -2107,13 +1477,20 @@ } } }, + "System.Private.Uri/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "Microsoft.NETCore.Targets": "1.1.3" + } + }, "System.Reflection/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", "System.IO": "4.3.0", "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Reflection": "4.3.0" } }, "System.Reflection.DispatchProxy/4.5.0": {}, @@ -2146,14 +1523,16 @@ "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", "System.Reflection": "4.3.0", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Reflection.Extensions": "4.3.0" } }, "System.Reflection.Primitives/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Reflection.Primitives": "4.3.0" } }, "System.Reflection.TypeExtensions/4.3.0": { @@ -2168,27 +1547,31 @@ "Microsoft.NETCore.Targets": "1.1.3", "System.Globalization": "4.3.0", "System.Reflection": "4.3.0", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Resources.ResourceManager": "4.3.0" } }, "System.Runtime/4.3.1": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", - "Microsoft.NETCore.Targets": "1.1.3" + "Microsoft.NETCore.Targets": "1.1.3", + "runtime.any.System.Runtime": "4.3.0" } }, "System.Runtime.Extensions/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.win.System.Runtime.Extensions": "4.3.0" } }, "System.Runtime.Handles/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Runtime.Handles": "4.3.0" } }, "System.Runtime.InteropServices/4.3.0": { @@ -2198,7 +1581,8 @@ "System.Reflection": "4.3.0", "System.Reflection.Primitives": "4.3.0", "System.Runtime": "4.3.1", - "System.Runtime.Handles": "4.3.0" + "System.Runtime.Handles": "4.3.0", + "runtime.any.System.Runtime.InteropServices": "4.3.0" } }, "System.Runtime.InteropServices.RuntimeInformation/4.3.0": { @@ -2212,6 +1596,13 @@ "runtime.native.System": "4.3.0" } }, + "System.Runtime.Loader/4.3.0": { + "dependencies": { + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.1" + } + }, "System.Runtime.Numerics/4.3.0": { "dependencies": { "System.Globalization": "4.3.0", @@ -2220,6 +1611,21 @@ "System.Runtime.Extensions": "4.3.0" } }, + "System.Runtime.Serialization.Formatters/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Serialization.Primitives": "4.3.0" + } + }, + "System.Runtime.Serialization.Primitives/4.3.0": { + "dependencies": { + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1" + } + }, "System.Security.AccessControl/4.7.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", @@ -2311,14 +1717,7 @@ "System.Threading.Tasks": "4.3.0" } }, - "System.Security.Cryptography.ProtectedData/8.0.0": { - "runtime": { - "lib/net8.0/System.Security.Cryptography.ProtectedData.dll": { - "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.23.53103" - } - } - }, + "System.Security.Cryptography.ProtectedData/8.0.0": {}, "System.Security.Cryptography.X509Certificates/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", @@ -2391,7 +1790,24 @@ "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Text.Encoding": "4.3.0" + } + }, + "System.Text.Encoding.CodePages/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "System.Collections": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0" } }, "System.Text.Encoding.Extensions/4.3.0": { @@ -2399,7 +1815,8 @@ "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", "System.Runtime": "4.3.1", - "System.Text.Encoding": "4.3.0" + "System.Text.Encoding": "4.3.0", + "runtime.any.System.Text.Encoding.Extensions": "4.3.0" } }, "System.Text.Encodings.Web/10.0.0": { @@ -2408,14 +1825,6 @@ "assemblyVersion": "10.0.0.0", "fileVersion": "10.0.25.52411" } - }, - "runtimeTargets": { - "runtimes/browser/lib/net8.0/System.Text.Encodings.Web.dll": { - "rid": "browser", - "assetType": "runtime", - "assemblyVersion": "10.0.0.0", - "fileVersion": "10.0.25.52411" - } } }, "System.Text.Json/10.0.0": { @@ -2430,7 +1839,7 @@ } } }, - "System.Text.RegularExpressions/4.3.0": { + "System.Text.RegularExpressions/4.3.1": { "dependencies": { "System.Runtime": "4.3.1" } @@ -2441,11 +1850,20 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.Threading.Overlapped/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "3.1.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Handles": "4.3.0" + } + }, "System.Threading.Tasks/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Threading.Tasks": "4.3.0" } }, "System.Threading.Tasks.Extensions/4.3.0": { @@ -2455,11 +1873,23 @@ "System.Threading.Tasks": "4.3.0" } }, + "System.Threading.Thread/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.1" + } + }, + "System.Threading.ThreadPool/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.1", + "System.Runtime.Handles": "4.3.0" + } + }, "System.Threading.Timer/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "3.1.0", "Microsoft.NETCore.Targets": "1.1.3", - "System.Runtime": "4.3.1" + "System.Runtime": "4.3.1", + "runtime.any.System.Threading.Timer": "4.3.0" } }, "System.Xml.ReaderWriter/4.3.0": { @@ -2476,7 +1906,7 @@ "System.Runtime.InteropServices": "4.3.0", "System.Text.Encoding": "4.3.0", "System.Text.Encoding.Extensions": "4.3.0", - "System.Text.RegularExpressions": "4.3.0", + "System.Text.RegularExpressions": "4.3.1", "System.Threading.Tasks": "4.3.0", "System.Threading.Tasks.Extensions": "4.3.0" } @@ -2497,6 +1927,20 @@ "System.Xml.ReaderWriter": "4.3.0" } }, + "System.Xml.XmlDocument/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.1", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0" + } + }, "Telerik.UI.for.Wpf.NetCore.Xaml/2024.1.408": { "dependencies": { "Microsoft.EntityFrameworkCore": "3.1.5", @@ -2786,15 +2230,16 @@ "dependencies": { "Emgu.CV": "4.10.0.5680", "Emgu.CV.Bitmap": "4.10.0.5680", - "Emgu.CV.runtime.windows": "4.10.0.5680", - "MahApps.Metro.IconPacks": "6.2.1", "Prism.DryIoc": "9.0.537", "Prism.Wpf": "9.0.537", "Serilog": "4.3.1", "XP.Common": "1.0.0" }, "runtime": { - "XP.Camera.dll": {} + "XP.Camera.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } }, "resources": { "en-US/XP.Camera.resources.dll": { @@ -2805,7 +2250,6 @@ "XP.Common/1.0.0": { "dependencies": { "Emgu.CV": "4.10.0.5680", - "Emgu.CV.runtime.windows": "4.10.0.5680", "Microsoft.Data.Sqlite": "10.0.3", "Prism.Wpf": "9.0.537", "Serilog": "4.3.1", @@ -2815,7 +2259,10 @@ "Telerik.UI.for.Wpf.NetCore.Xaml": "2024.1.408" }, "runtime": { - "XP.Common.dll": {} + "XP.Common.dll": { + "assemblyVersion": "1.4.16.1", + "fileVersion": "1.4.16.1" + } }, "resources": { "en-US/XP.Common.resources.dll": { @@ -2836,7 +2283,10 @@ "XP.Common": "1.0.0" }, "runtime": { - "XP.Hardware.Detector.dll": {} + "XP.Hardware.Detector.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } }, "resources": { "en-US/XP.Hardware.Detector.resources.dll": { @@ -2859,7 +2309,10 @@ "XP.Hardware.PLC": "1.0.0" }, "runtime": { - "XP.Hardware.MotionControl.dll": {} + "XP.Hardware.MotionControl.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } }, "resources": { "en-US/XP.Hardware.MotionControl.resources.dll": { @@ -2880,7 +2333,10 @@ "XP.Common": "1.0.0" }, "runtime": { - "XP.Hardware.PLC.dll": {} + "XP.Hardware.PLC.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } }, "resources": { "en-US/XP.Hardware.PLC.resources.dll": { @@ -2903,7 +2359,10 @@ "XP.Hardware.RaySource.Comet.Messages": "1.0.0" }, "runtime": { - "XP.Hardware.RaySource.dll": {} + "XP.Hardware.RaySource.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } }, "resources": { "en-US/XP.Hardware.RaySource.resources.dll": { @@ -2922,17 +2381,21 @@ "Newtonsoft.Json": "13.0.3" }, "runtime": { - "XP.Hardware.RaySource.Comet.Messages.dll": {} + "XP.Hardware.RaySource.Comet.Messages.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } } }, "XP.ImageProcessing.CfgControl/1.0.0": { "dependencies": { - "MahApps.Metro": "2.4.11", - "MahApps.Metro.IconPacks": "6.2.1", "XP.ImageProcessing.Core": "1.0.0" }, "runtime": { - "XP.ImageProcessing.CfgControl.dll": {} + "XP.ImageProcessing.CfgControl.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } }, "resources": { "zh-CN/XP.ImageProcessing.CfgControl.resources.dll": { @@ -2942,18 +2405,19 @@ }, "XP.ImageProcessing.Core/1.0.0": { "dependencies": { - "Emgu.CV": "4.10.0.5680", - "Emgu.CV.runtime.windows": "4.10.0.5680" + "Emgu.CV": "4.10.0.5680" }, "runtime": { - "XP.ImageProcessing.Core.dll": {} + "XP.ImageProcessing.Core.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } } }, "XP.ImageProcessing.Processors/1.0.0": { "dependencies": { "Emgu.CV": "4.10.0.5680", "Emgu.CV.Bitmap": "4.10.0.5680", - "Emgu.CV.runtime.windows": "4.10.0.5680", "Microsoft.ML.OnnxRuntime.Gpu": "1.20.1", "Serilog": "4.3.1", "Serilog.Sinks.Console": "6.1.1", @@ -2961,7 +2425,10 @@ "XP.ImageProcessing.Core": "1.0.0" }, "runtime": { - "XP.ImageProcessing.Processors.dll": {} + "XP.ImageProcessing.Processors.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } }, "resources": { "zh-CN/XP.ImageProcessing.Processors.resources.dll": { @@ -2974,7 +2441,37 @@ "Microsoft.Xaml.Behaviors.Wpf": "1.1.122" }, "runtime": { - "XP.ImageProcessing.RoiControl.dll": {} + "XP.ImageProcessing.RoiControl.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "XP.ReportEngine/1.0.0": { + "dependencies": { + "Newtonsoft.Json": "13.0.3", + "Prism.Wpf": "9.0.537", + "Telerik.UI.for.Wpf.NetCore.Xaml": "2024.1.408", + "XP.Common": "1.0.0", + "itext7": "8.0.5", + "itext7.bouncy-castle-adapter": "8.0.5" + }, + "runtime": { + "XP.ReportEngine.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + }, + "resources": { + "en-US/XP.ReportEngine.resources.dll": { + "locale": "en-US" + }, + "zh-CN/XP.ReportEngine.resources.dll": { + "locale": "zh-CN" + }, + "zh-TW/XP.ReportEngine.resources.dll": { + "locale": "zh-TW" + } } }, "BR.AN.PviServices/1.1.0.0": { @@ -3009,6 +2506,13 @@ "serviceable": false, "sha512": "" }, + "BouncyCastle.Cryptography/2.2.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-A6Zr52zVqJKt18ZBsTnX0qhG0kwIQftVAjLmszmkiR/trSp8H+xj1gUOzk7XHwaKgyREMSV1v9XaKrBUeIOdvQ==", + "path": "bouncycastle.cryptography/2.2.1", + "hashPath": "bouncycastle.cryptography.2.2.1.nupkg.sha512" + }, "ControlzEx/5.0.1": { "type": "package", "serviceable": true, @@ -3079,320 +2583,40 @@ "path": "fluent.ribbon/9.0.0", "hashPath": "fluent.ribbon.9.0.0.nupkg.sha512" }, - "MahApps.Metro/2.4.11": { + "itext/8.0.5": { "type": "package", "serviceable": true, - "sha512": "sha512-pvk757N/ViZy+zlbB56AakryuZkts328M6pX2mMn/Z7r5ifkScDrS300zSBjLd+eGOPeHgUjH4f7cZbRiMyvQg==", - "path": "mahapps.metro/2.4.11", - "hashPath": "mahapps.metro.2.4.11.nupkg.sha512" + "sha512": "sha512-AptrL1Kvm4SrrkZSSfvQF9heRHekr9R91gR/3hEFR0uxJlBdVMmVnPQiTS+AhxJwalNtGNytKeFMWRoEUpWuTg==", + "path": "itext/8.0.5", + "hashPath": "itext.8.0.5.nupkg.sha512" }, - "MahApps.Metro.IconPacks/6.2.1": { + "itext.bouncy-castle-adapter/8.0.5": { "type": "package", "serviceable": true, - "sha512": "sha512-D4iq02tGW42jn0go7M+mBI8uMkfAmUrPwQl9gaV3WqiIssjABwP9vAtU05NTWUx9lB0xl+YlfcnVfFoKki0Ylw==", - "path": "mahapps.metro.iconpacks/6.2.1", - "hashPath": "mahapps.metro.iconpacks.6.2.1.nupkg.sha512" + "sha512": "sha512-mam0CtYkKmVwdX7wU1Zlg9oVW0B9efMASfAEIm+fQGovc9HcplsmP3MylS+VmQHbYlCNSH68DQlVhDz6Cu9WxQ==", + "path": "itext.bouncy-castle-adapter/8.0.5", + "hashPath": "itext.bouncy-castle-adapter.8.0.5.nupkg.sha512" }, - "MahApps.Metro.IconPacks.BootstrapIcons/6.2.1": { + "itext.commons/8.0.5": { "type": "package", "serviceable": true, - "sha512": "sha512-dTd5CaF63Ke2mWKlpagKEoU7sQmAtpoTyIMrZulPtI8N6OEkA6my3ekTPEt0OHu68zjiiXzZA5HLH2dlHUX+9w==", - "path": "mahapps.metro.iconpacks.bootstrapicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.bootstrapicons.6.2.1.nupkg.sha512" + "sha512": "sha512-exnLqeWOnn0Ee393bHf3zWTmcYuQfYuj7iIbMluG49XFczMWMMXrN9UvMmt5iYOKq0mGZsYb1eRoVATGuDiXGQ==", + "path": "itext.commons/8.0.5", + "hashPath": "itext.commons.8.0.5.nupkg.sha512" }, - "MahApps.Metro.IconPacks.BoxIcons/6.2.1": { + "itext7/8.0.5": { "type": "package", "serviceable": true, - "sha512": "sha512-fvxelxwj1Fr+osvmJnvlSthN34ZpwWMDacCWSGpylw8Pz+bFWcPIA3DxDMbxshvUhZ5dYzigCOxHZKG/BHPEdw==", - "path": "mahapps.metro.iconpacks.boxicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.boxicons.6.2.1.nupkg.sha512" + "sha512": "sha512-/1btEFYY+ncIR7j/g+pr26PX8Nbly8pbdDWfSHQq9E/rbxhz0ylkOLVpXNEvoaV545q508P8hociHaRiRG7bwg==", + "path": "itext7/8.0.5", + "hashPath": "itext7.8.0.5.nupkg.sha512" }, - "MahApps.Metro.IconPacks.BoxIcons2/6.2.1": { + "itext7.bouncy-castle-adapter/8.0.5": { "type": "package", "serviceable": true, - "sha512": "sha512-TkTvGg1L/w3kCGB7D7Hqd3EhYevijeknuh/VGVsaF47J4eOwf42Y2zXV7rpCXAY13zfrGWCq8RQQdacwFStQow==", - "path": "mahapps.metro.iconpacks.boxicons2/6.2.1", - "hashPath": "mahapps.metro.iconpacks.boxicons2.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.CircumIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-6L+lBg3Cj8Tq1TK0FHIBvS4t9iDa9V966dGZrzNAryZD/jQ2ncvz4rIDsZpSnsrLIhxMqChLvNogg3sDEuchtA==", - "path": "mahapps.metro.iconpacks.circumicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.circumicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Codicons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-+pQeVS29X7pG7qrJ4y0ZPSRUQVaWidwwM/tdoIABo40MQpC0Izg8t1BXnXprP0C10Od9Zzsi2Qt/GWgfEW/aSw==", - "path": "mahapps.metro.iconpacks.codicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.codicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Coolicons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-YdAqLEsLON2ripNNXkzrVX3iHQgEVXvfcvChx/2UsFyefV63RMVRu1rXCtLrOGRm/NAl7okTu2d6IeUVj+bCFQ==", - "path": "mahapps.metro.iconpacks.coolicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.coolicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Core/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-ySAyax37C045Ef1ufN33yQjn3qPM1MuQLgKdxZKYUAl2uZaIrn9wCeBNvfG46QPNRvBFLR6gVKTs6O3o81LNhQ==", - "path": "mahapps.metro.iconpacks.core/6.2.1", - "hashPath": "mahapps.metro.iconpacks.core.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Entypo/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-H1xzNFcF1gPgkrMFT3RgVc+whTZ88+g1hFUzaRkZYjH7k4JGGxsb6dqVjHyMQCbSygCUiWNuzy0yzNrv1krQOg==", - "path": "mahapps.metro.iconpacks.entypo/6.2.1", - "hashPath": "mahapps.metro.iconpacks.entypo.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.EvaIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-bUQfSeAb0uphQrhks3Mhj5kk+WsqL22dPF5b9DSVrRi7bHgWt2+ciMZZp85Q+zFKtHM3PkdGC2nUbl0bBu6AyQ==", - "path": "mahapps.metro.iconpacks.evaicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.evaicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.FeatherIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-a5sxUHp39ejJu6p2wbbJT71tYY4zYuS+N4Vb9VxcnsQqaeMktuHtiy1ySR43h4dkdzhAohbyxvb9j80AkDXZLA==", - "path": "mahapps.metro.iconpacks.feathericons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.feathericons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.FileIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-Rir1rKL8LNhxhWNmVdWDbSRjoJg+y0t4kqDdD5zLH6T7uFm6yjPvIEK4pvA30NIFPgvl4bkN2TKQLv+7P4FNDw==", - "path": "mahapps.metro.iconpacks.fileicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.fileicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Fontaudio/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-AsYb9vBKtkYBPV/3OEGTijH+wrlxxPcMFRXVbbRZLz1E9JIoGxkRcwnFryWs2bhDIMiLVzj2DgYClqvJSovmEw==", - "path": "mahapps.metro.iconpacks.fontaudio/6.2.1", - "hashPath": "mahapps.metro.iconpacks.fontaudio.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.FontAwesome/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-Su6jzajwH8rP7H5OGhXvyC2SlsoyH0pNwNCkDFSP5zyVQlMtmUZGOY8X0Qcj1QFn+t4TmEnMjwGMB6RuzozgEg==", - "path": "mahapps.metro.iconpacks.fontawesome/6.2.1", - "hashPath": "mahapps.metro.iconpacks.fontawesome.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.FontAwesome5/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-PNTiFAT/+ro1SitUj8k+gGWDq7mC/eYD1cy8QfF84ZyCp+goLh5BApj0IGvv+eisLMw7hFIIzI8vIHQ1GbyExw==", - "path": "mahapps.metro.iconpacks.fontawesome5/6.2.1", - "hashPath": "mahapps.metro.iconpacks.fontawesome5.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.FontAwesome6/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-IB2AdqnGAdM2RK8Ekmf8U2VBw7cAnRQHQaVJ1Kv/0Ek+VavsmUqlyotmSg28iL4Sq9BBC2SQrRbvuIGfz9seWA==", - "path": "mahapps.metro.iconpacks.fontawesome6/6.2.1", - "hashPath": "mahapps.metro.iconpacks.fontawesome6.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Fontisto/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-+JDR5+YpYq/iBdj7DZiT5XA4U5+I2kxqxGK6usqOi077iemIEXKWxhrEiWyruHfRQt4VrD/WGy27PrJzU/h6cA==", - "path": "mahapps.metro.iconpacks.fontisto/6.2.1", - "hashPath": "mahapps.metro.iconpacks.fontisto.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.ForkAwesome/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-luVbeZF3hH7DQl+QCT6NV9vGJ8a1CtOJd0W2AShOms8YuAU4RnsHMm9jrrONpCBeVqQI8mpFRTzd0bYit8gilg==", - "path": "mahapps.metro.iconpacks.forkawesome/6.2.1", - "hashPath": "mahapps.metro.iconpacks.forkawesome.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.GameIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-oOVAHye1k+cjfXaGfBP6nu5AtZND65WhsolAqmS8wMtM5wPN5q0k8jUq3lxm5/MRMh+rCT99oAcZKmyDaRlcVA==", - "path": "mahapps.metro.iconpacks.gameicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.gameicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Ionicons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-WBHtfiUfEGUPiLaJkQ2ZXipo01eRbW6PM6qI7S4LLPGs5FM9YIy6PiaeahN8FcYS/HnYx8E2HSJ99R+U+M2nBA==", - "path": "mahapps.metro.iconpacks.ionicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.ionicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.JamIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-9Jc2IzyBa0vASPCup7woKHTSwG31rtBvZsdpA+Jot++eWkZpvCpgWn8BKdcNcIh3Hjnve9qLzPWb11WobPO2CQ==", - "path": "mahapps.metro.iconpacks.jamicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.jamicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.KeyruneIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-9Cs7gIl1WCTsZHPgX0Ri32r8vTPi32Zxf/z/3CxLpfksY7qsTodCWWWlIgjEqxriWE/AGoUzdh1o73j5qtQ/RQ==", - "path": "mahapps.metro.iconpacks.keyruneicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.keyruneicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Lucide/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-xehG2J/Ljfa6NxlKCqvDxnxUMrApR0xSLGaoaFSVN531jF+WNZNAaUvE9qkxOHKZ+jpH4gUnb2sC3qNcpAGVkA==", - "path": "mahapps.metro.iconpacks.lucide/6.2.1", - "hashPath": "mahapps.metro.iconpacks.lucide.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Material/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-DcNQIsJLAmuzlpXdD2hQtMV8IzLRHsxFBn9+nHDLAsYs8duTBTycpNpQitkzuNYH0o+sgIbefCSp3jDUu9hIiQ==", - "path": "mahapps.metro.iconpacks.material/6.2.1", - "hashPath": "mahapps.metro.iconpacks.material.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.MaterialDesign/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-qMQHCZzHoBZy3bcU9CBf9GusPMpbxy0DPxiJrfbhM7IHh/hK5xWREoP2TOevqAVTEOk3YszWbiJBkYo/oeEliw==", - "path": "mahapps.metro.iconpacks.materialdesign/6.2.1", - "hashPath": "mahapps.metro.iconpacks.materialdesign.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.MaterialLight/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-8ypOe4HwSGnoQl/JIpC5hb6VnK+xFtSbvhlTmw+cnJVNluiwWdpJv+m9jpU3/9+SRkJRHVgHvEMwEXQx/XmS4A==", - "path": "mahapps.metro.iconpacks.materiallight/6.2.1", - "hashPath": "mahapps.metro.iconpacks.materiallight.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.MemoryIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-TIU3n0ZXhKgpSaSlqg3EEjPBp+E89UyV6nOhK4DCP9yUbnZ/CuLmkwrrd2rtt9au+VD+TB1lWbA6+3NjpH7G9Q==", - "path": "mahapps.metro.iconpacks.memoryicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.memoryicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Microns/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-stnuTZXy+k7BmKGvI4oP0NlspElhernJ4yFXUlEkA3X/38qlqq+YltM5KPPKgQo1BLHj58lOOn+U03grfdPI5A==", - "path": "mahapps.metro.iconpacks.microns/6.2.1", - "hashPath": "mahapps.metro.iconpacks.microns.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.MingCuteIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-AfMV+SbqWabsuQdS6wt7SpinS5cah+7Pkdj+bfhHBBizdMsL+nY8+tiwmKF1up+wfZm8lCvnrCQWTkJ2mMSjUA==", - "path": "mahapps.metro.iconpacks.mingcuteicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.mingcuteicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Modern/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-xCDNREDX37HZE1YIAwQ9YOwwhQLHRby1ec1FwLKRU6MWX0OJuceqk3HY3532xG7KpGGaOIV/dpB5vFq3oo+wug==", - "path": "mahapps.metro.iconpacks.modern/6.2.1", - "hashPath": "mahapps.metro.iconpacks.modern.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.MynaUIIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-StYsKBuK2kKfUdkKq6ZDa5xtlWk4gyI59ip9mS30niYxn4K0yAZIMEyx1EX4efpGanlLF4oPGZ/YUvWGfl98NA==", - "path": "mahapps.metro.iconpacks.mynauiicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.mynauiicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Octicons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-1WGEPYjdcOMgXNspZHhYXooNJbylZyqLAkzXiCvlu1pW6HinBzaJI+vSkPtoZaF9QaMkSxwT2ZxG4mMkbhUowA==", - "path": "mahapps.metro.iconpacks.octicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.octicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.PhosphorIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-PTfhQXTe3INWoELJy0dCfm92/faS6hF3F/C4kZyTiVe9Pgf21cd5v7kIBeT2m/eNHyEBFZX2ifmk8Q3xK1dr7g==", - "path": "mahapps.metro.iconpacks.phosphoricons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.phosphoricons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.PicolIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-6lEuXdF77v9Ip4QoDEJm7+mrfVRz7EV3LJGxDzVfPsSPwA4VxIsqOU0xHKDQ/5Ekv+gPXW/PQtecfjlQ+UrWGw==", - "path": "mahapps.metro.iconpacks.picolicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.picolicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.PixelartIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-KJwxtRvqpMHRkghru0H7AZcDgUDpgNq4bQTclivcQyUTChedfZh64REfJ1B5QCfKdCKmvVMR66JpJnGoM6ekdA==", - "path": "mahapps.metro.iconpacks.pixelarticons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.pixelarticons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.RadixIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-1COtOqMAtgOydnx8cU/ukwNn4KRAzaFp5+SCucYgjyq0vdm1+1hi8inNDEZvIJqAhCSdCU13afFhsL/1KYLbBQ==", - "path": "mahapps.metro.iconpacks.radixicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.radixicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.RemixIcon/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-ROcfFFN2S45IV7dqU6Alf8i5gMIG+4iArm8Mzb+KXjiyLOHpTZ/QHGIy9DtqIG4NuCO9pwf+fNTGCsDlXIG3TQ==", - "path": "mahapps.metro.iconpacks.remixicon/6.2.1", - "hashPath": "mahapps.metro.iconpacks.remixicon.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.RPGAwesome/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-6zHlSIU5z5meUIjDpwX872Z9Zd1ZhBRuohWiy0a+AUevdOpPw9or7rGpiMAdAzEvmab4sy9Un787A4YC5LQr7w==", - "path": "mahapps.metro.iconpacks.rpgawesome/6.2.1", - "hashPath": "mahapps.metro.iconpacks.rpgawesome.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.SimpleIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-EbK+/s00A72ATU+Qpk72ZxQsLvVGGRD8UA/jsGDqV0Hlym0I//dtQjYwWxzfwmTp2Ay3Sh6RmLu49qqv3Ey2/Q==", - "path": "mahapps.metro.iconpacks.simpleicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.simpleicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Typicons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-o6kNl3wKxsO1MkgRg8V/wY7un1ueNBbqy5Ut3Y46mC2vVzEwxcejss5+BtuO/oFud3GQtet2Ng53z+70dNjG4Q==", - "path": "mahapps.metro.iconpacks.typicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.typicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Unicons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-JdTZD7CtLjcf+Ne0jN6EsyvG/Dl+v4w08OQRSC9XTknuVW/zlJyHcxbJy+NvkBdcO+Jup/TwNslV5g9xVheavQ==", - "path": "mahapps.metro.iconpacks.unicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.unicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.VaadinIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-6GOuzyvLNojG+NLZDULsWSfQ+RAh2v8W6n2iPWc+c1pDcmgbuKCPiazQXb0YpPuldGEOpK1ur6WJOXXsrTRR6A==", - "path": "mahapps.metro.iconpacks.vaadinicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.vaadinicons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.WeatherIcons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-ChU6387+6rDPQZRS/L7wT4YFMmSvv0AdeCBAPVZTeW3SdeFt49tOWQvz2Xpb+N55Qn4tGjb+/lE2dg/NAYYU2w==", - "path": "mahapps.metro.iconpacks.weathericons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.weathericons.6.2.1.nupkg.sha512" - }, - "MahApps.Metro.IconPacks.Zondicons/6.2.1": { - "type": "package", - "serviceable": true, - "sha512": "sha512-6+IMX7VptiD05ctXsjhEcvBHx0Gbj4DH1j13Ko5gk9yO7m6cCYaWqsKlt/GMH5CJEfa7Obz9+1pRstOzxZ03+A==", - "path": "mahapps.metro.iconpacks.zondicons/6.2.1", - "hashPath": "mahapps.metro.iconpacks.zondicons.6.2.1.nupkg.sha512" + "sha512": "sha512-9jpalaOyxbcuhbl9yJJQGXdseKUFrKlUjjcjIvReb3Qz4Aw0F+WNXKOo0sax87TGGNb66fyHsfJib3JTnfzRYw==", + "path": "itext7.bouncy-castle-adapter/8.0.5", + "hashPath": "itext7.bouncy-castle-adapter.8.0.5.nupkg.sha512" }, "Microsoft.Bcl.AsyncInterfaces/1.1.1": { "type": "package", @@ -3429,6 +2653,13 @@ "path": "microsoft.data.sqlite.core/10.0.3", "hashPath": "microsoft.data.sqlite.core.10.0.3.nupkg.sha512" }, + "Microsoft.DotNet.PlatformAbstractions/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Bl6KYfbFSIW3QIRHAp931iR5h01qHjKghdpAtncwbzNUs0+IUZ+XfwkIU0sQsR33ufGvi3u4dZMIYYFysjpHAA==", + "path": "microsoft.dotnet.platformabstractions/1.1.0", + "hashPath": "microsoft.dotnet.platformabstractions.1.1.0.nupkg.sha512" + }, "Microsoft.EntityFrameworkCore/3.1.5": { "type": "package", "serviceable": true, @@ -3485,12 +2716,12 @@ "path": "microsoft.extensions.configuration.binder/10.0.0", "hashPath": "microsoft.extensions.configuration.binder.10.0.0.nupkg.sha512" }, - "Microsoft.Extensions.DependencyInjection/3.1.5": { + "Microsoft.Extensions.DependencyInjection/5.0.0": { "type": "package", "serviceable": true, - "sha512": "sha512-I+RTJQi7TtenIHZqL2zr6523PYXfL88Ruu4UIVmspIxdw14GHd8zZ+2dGLSdwX7fn41Hth4d42S1e1iHWVOJyQ==", - "path": "microsoft.extensions.dependencyinjection/3.1.5", - "hashPath": "microsoft.extensions.dependencyinjection.3.1.5.nupkg.sha512" + "sha512": "sha512-Rc2kb/p3Ze6cP6rhFC3PJRdWGbLvSHZc0ev7YlyeU6FmHciDMLrhoVoTUEzKPhN5ZjFgKF1Cf5fOz8mCMIkvpA==", + "path": "microsoft.extensions.dependencyinjection/5.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.5.0.0.nupkg.sha512" }, "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.1": { "type": "package", @@ -3506,26 +2737,26 @@ "path": "microsoft.extensions.dependencymodel/10.0.0", "hashPath": "microsoft.extensions.dependencymodel.10.0.0.nupkg.sha512" }, - "Microsoft.Extensions.Logging/3.1.5": { + "Microsoft.Extensions.Logging/5.0.0": { "type": "package", "serviceable": true, - "sha512": "sha512-C85NYDym6xy03o70vxX+VQ4ZEjj5Eg5t5QoGW0t100vG5MmPL6+G3XXcQjIIn1WRQrjzGWzQwuKf38fxXEWIWA==", - "path": "microsoft.extensions.logging/3.1.5", - "hashPath": "microsoft.extensions.logging.3.1.5.nupkg.sha512" + "sha512": "sha512-MgOwK6tPzB6YNH21wssJcw/2MKwee8b2gI7SllYfn6rvTpIrVvVS5HAjSU2vqSku1fwqRvWP0MdIi14qjd93Aw==", + "path": "microsoft.extensions.logging/5.0.0", + "hashPath": "microsoft.extensions.logging.5.0.0.nupkg.sha512" }, - "Microsoft.Extensions.Logging.Abstractions/3.1.5": { + "Microsoft.Extensions.Logging.Abstractions/5.0.0": { "type": "package", "serviceable": true, - "sha512": "sha512-ZvwowjRSWXewdPI+whPFXgwF4Qme6Q9KV9SCPEITSGiqHLArct7q5hTBtTzj3GPsVLjTqehvTg6Bd/EQk9JS0A==", - "path": "microsoft.extensions.logging.abstractions/3.1.5", - "hashPath": "microsoft.extensions.logging.abstractions.3.1.5.nupkg.sha512" + "sha512": "sha512-NxP6ahFcBnnSfwNBi2KH2Oz8Xl5Sm2krjId/jRR3I7teFphwiUoUeZPwTNA21EX+5PtjqmyAvKaOeBXcJjcH/w==", + "path": "microsoft.extensions.logging.abstractions/5.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.5.0.0.nupkg.sha512" }, - "Microsoft.Extensions.Options/3.1.5": { + "Microsoft.Extensions.Options/5.0.0": { "type": "package", "serviceable": true, - "sha512": "sha512-f+JT/7lkKBMp/Ak2tVjO+TD7o+UoCfjnExkZNn0PZIso8kIXrqNy6x42Lrxf4Q0pW3JMf9ExmL2EQlvk2XnFAg==", - "path": "microsoft.extensions.options/3.1.5", - "hashPath": "microsoft.extensions.options.3.1.5.nupkg.sha512" + "sha512": "sha512-CBvR92TCJ5uBIdd9/HzDSrxYak+0W/3+yxrNg8Qm6Bmrkh5L+nu6m3WeazQehcZ5q1/6dDA7J5YdQjim0165zg==", + "path": "microsoft.extensions.options/5.0.0", + "hashPath": "microsoft.extensions.options.5.0.0.nupkg.sha512" }, "Microsoft.Extensions.Primitives/10.0.0": { "type": "package", @@ -3688,6 +2919,125 @@ "path": "prism.wpf/9.0.537", "hashPath": "prism.wpf.9.0.537.nupkg.sha512" }, + "runtime.any.System.Collections/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-23g6rqftKmovn2cLeGsuHUYm0FD7pdutb0uQMJpZ3qTvq+zHkgmt6J65VtRry4WDGYlmkMa4xDACtaQ94alNag==", + "path": "runtime.any.system.collections/4.3.0", + "hashPath": "runtime.any.system.collections.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Diagnostics.Tools/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-S/GPBmfPBB48ZghLxdDR7kDAJVAqgAuThyDJho3OLP5OS4tWD2ydyL8LKm8lhiBxce10OKe9X2zZ6DUjAqEbPg==", + "path": "runtime.any.system.diagnostics.tools/4.3.0", + "hashPath": "runtime.any.system.diagnostics.tools.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Diagnostics.Tracing/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-1lpifymjGDzoYIaam6/Hyqf8GhBI3xXYLK2TgEvTtuZMorG3Kb9QnMTIKhLjJYXIiu1JvxjngHvtVFQQlpQ3HQ==", + "path": "runtime.any.system.diagnostics.tracing/4.3.0", + "hashPath": "runtime.any.system.diagnostics.tracing.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Globalization/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-sMDBnad4rp4t7GY442Jux0MCUuKL4otn5BK6Ni0ARTXTSpRNBzZ7hpMfKSvnVSED5kYJm96YOWsqV0JH0d2uuw==", + "path": "runtime.any.system.globalization/4.3.0", + "hashPath": "runtime.any.system.globalization.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Globalization.Calendars/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-M1r+760j1CNA6M/ZaW6KX8gOS8nxPRqloqDcJYVidRG566Ykwcs29AweZs2JF+nMOCgWDiMfPSTMfvwOI9F77w==", + "path": "runtime.any.system.globalization.calendars/4.3.0", + "hashPath": "runtime.any.system.globalization.calendars.4.3.0.nupkg.sha512" + }, + "runtime.any.System.IO/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-SDZ5AD1DtyRoxYtEcqQ3HDlcrorMYXZeCt7ZhG9US9I5Vva+gpIWDGMkcwa5XiKL0ceQKRZIX2x0XEjLX7PDzQ==", + "path": "runtime.any.system.io/4.3.0", + "hashPath": "runtime.any.system.io.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Reflection/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-hLC3A3rI8jipR5d9k7+f0MgRCW6texsAp0MWkN/ci18FMtQ9KH7E2vDn/DH2LkxsszlpJpOn9qy6Z6/69rH6eQ==", + "path": "runtime.any.system.reflection/4.3.0", + "hashPath": "runtime.any.system.reflection.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Reflection.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cPhT+Vqu52+cQQrDai/V91gubXUnDKNRvlBnH+hOgtGyHdC17aQIU64EaehwAQymd7kJA5rSrVRNfDYrbhnzyA==", + "path": "runtime.any.system.reflection.extensions/4.3.0", + "hashPath": "runtime.any.system.reflection.extensions.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Reflection.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nrm1p3armp6TTf2xuvaa+jGTTmncALWFq22CpmwRvhDf6dE9ZmH40EbOswD4GnFLrMRS0Ki6Kx5aUPmKK/hZBg==", + "path": "runtime.any.system.reflection.primitives/4.3.0", + "hashPath": "runtime.any.system.reflection.primitives.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Resources.ResourceManager/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Lxb89SMvf8w9p9+keBLyL6H6x/TEmc6QVsIIA0T36IuyOY3kNvIdyGddA2qt35cRamzxF8K5p0Opq4G4HjNbhQ==", + "path": "runtime.any.system.resources.resourcemanager/4.3.0", + "hashPath": "runtime.any.system.resources.resourcemanager.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Runtime/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-fRS7zJgaG9NkifaAxGGclDDoRn9HC7hXACl52Or06a/fxdzDajWb5wov3c6a+gVSlekRoexfjwQSK9sh5um5LQ==", + "path": "runtime.any.system.runtime/4.3.0", + "hashPath": "runtime.any.system.runtime.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Runtime.Handles/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-GG84X6vufoEzqx8PbeBKheE4srOhimv+yLtGb/JkR3Y2FmoqmueLNFU4Xx8Y67plFpltQSdK74x0qlEhIpv/CQ==", + "path": "runtime.any.system.runtime.handles/4.3.0", + "hashPath": "runtime.any.system.runtime.handles.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Runtime.InteropServices/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lBoFeQfxe/4eqjPi46E0LU/YaCMdNkQ8B4MZu/mkzdIAZh8RQ1NYZSj0egrQKdgdvlPFtP4STtob40r4o2DBAw==", + "path": "runtime.any.system.runtime.interopservices/4.3.0", + "hashPath": "runtime.any.system.runtime.interopservices.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Text.Encoding/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+ihI5VaXFCMVPJNstG4O4eo1CfbrByLxRrQQTqOTp1ttK0kUKDqOdBSTaCB2IBk/QtjDrs6+x4xuezyMXdm0HQ==", + "path": "runtime.any.system.text.encoding/4.3.0", + "hashPath": "runtime.any.system.text.encoding.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Text.Encoding.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NLrxmLsfRrOuVqPWG+2lrQZnE53MLVeo+w9c54EV+TUo4c8rILpsDXfY8pPiOy9kHpUHHP07ugKmtsU3vVW5Jg==", + "path": "runtime.any.system.text.encoding.extensions/4.3.0", + "hashPath": "runtime.any.system.text.encoding.extensions.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Threading.Tasks/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OhBAVBQG5kFj1S+hCEQ3TUHBAEtZ3fbEMgZMRNdN8A0Pj4x+5nTELEqL59DU0TjKVE6II3dqKw4Dklb3szT65w==", + "path": "runtime.any.system.threading.tasks/4.3.0", + "hashPath": "runtime.any.system.threading.tasks.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Threading.Timer/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-w4ehZJ+AwXYmGwYu+rMvym6RvMaRiUEQR1u6dwcyuKHxz8Heu/mO9AG1MquEgTyucnhv3M43X0iKpDOoN17C0w==", + "path": "runtime.any.system.threading.timer/4.3.0", + "hashPath": "runtime.any.system.threading.timer.4.3.0.nupkg.sha512" + }, "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": { "type": "package", "serviceable": true, @@ -3828,6 +3178,55 @@ "path": "runtime.win-x86.runtime.native.system.data.sqlclient.sni/4.4.0", "hashPath": "runtime.win-x86.runtime.native.system.data.sqlclient.sni.4.4.0.nupkg.sha512" }, + "runtime.win.Microsoft.Win32.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NU51SEt/ZaD2MF48sJ17BIqx7rjeNNLXUevfMOjqQIetdndXwYjZfZsT6jD+rSWp/FYxjesdK4xUSl4OTEI0jw==", + "path": "runtime.win.microsoft.win32.primitives/4.3.0", + "hashPath": "runtime.win.microsoft.win32.primitives.4.3.0.nupkg.sha512" + }, + "runtime.win.System.Console/4.3.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-vHPXC3B18dxhyipVce8xQT1MQv1o5srYZqBlCNu9p9MNjhgGOntdQh/Xh2X4o7M2F839YUcQiGwu8Q498FyDjg==", + "path": "runtime.win.system.console/4.3.1", + "hashPath": "runtime.win.system.console.4.3.1.nupkg.sha512" + }, + "runtime.win.System.Diagnostics.Debug/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-hHHP0WCStene2jjeYcuDkETozUYF/3sHVRHAEOgS3L15hlip24ssqCTnJC28Z03Wpo078oMcJd0H4egD2aJI8g==", + "path": "runtime.win.system.diagnostics.debug/4.3.0", + "hashPath": "runtime.win.system.diagnostics.debug.4.3.0.nupkg.sha512" + }, + "runtime.win.System.IO.FileSystem/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Z37zcSCpXuGCYtFbqYO0TwOVXxS2d+BXgSoDFZmRg8BC4Cuy54edjyIvhhcfCrDQA9nl+EPFTgHN54dRAK7mNA==", + "path": "runtime.win.system.io.filesystem/4.3.0", + "hashPath": "runtime.win.system.io.filesystem.4.3.0.nupkg.sha512" + }, + "runtime.win.System.Net.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lkXXykakvXUU+Zq2j0pC6EO20lEhijjqMc01XXpp1CJN+DeCwl3nsj4t5Xbpz3kA7yQyTqw6d9SyIzsyLsV3zA==", + "path": "runtime.win.system.net.primitives/4.3.0", + "hashPath": "runtime.win.system.net.primitives.4.3.0.nupkg.sha512" + }, + "runtime.win.System.Net.Sockets/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FK/2gX6MmuLIKNCGsV59Fe4IYrLrI5n9pQ1jh477wiivEM/NCXDT2dRetH5FSfY0bQ+VgTLcS3zcmjQ8my3nxQ==", + "path": "runtime.win.system.net.sockets/4.3.0", + "hashPath": "runtime.win.system.net.sockets.4.3.0.nupkg.sha512" + }, + "runtime.win.System.Runtime.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-RkgHVhUPvzZxuUubiZe8yr/6CypRVXj0VBzaR8hsqQ8f+rUo7e4PWrHTLOCjd8fBMGWCrY//fi7Ku3qXD7oHRw==", + "path": "runtime.win.system.runtime.extensions/4.3.0", + "hashPath": "runtime.win.system.runtime.extensions.4.3.0.nupkg.sha512" + }, "Serilog/4.3.1": { "type": "package", "serviceable": true, @@ -3989,6 +3388,13 @@ "path": "system.collections.immutable/1.7.1", "hashPath": "system.collections.immutable.1.7.1.nupkg.sha512" }, + "System.Collections.NonGeneric/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-prtjIEMhGUnQq6RnPEYLpFt8AtLbp9yq2zxOSrY7KJJZrw25Fi97IzBqY7iqssbM61Ek5b8f3MG/sG1N2sN5KA==", + "path": "system.collections.nongeneric/4.3.0", + "hashPath": "system.collections.nongeneric.4.3.0.nupkg.sha512" + }, "System.ComponentModel.Annotations/4.7.0": { "type": "package", "serviceable": true, @@ -4073,6 +3479,13 @@ "path": "system.diagnostics.performancecounter/6.0.0", "hashPath": "system.diagnostics.performancecounter.6.0.0.nupkg.sha512" }, + "System.Diagnostics.Process/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-J0wOX07+QASQblsfxmIMFc9Iq7KTXYL3zs2G/Xc704Ylv3NpuVdo6gij6V3PGiptTxqsK0K7CdXenRvKUnkA2g==", + "path": "system.diagnostics.process/4.3.0", + "hashPath": "system.diagnostics.process.4.3.0.nupkg.sha512" + }, "System.Diagnostics.Tools/4.3.0": { "type": "package", "serviceable": true, @@ -4192,6 +3605,13 @@ "path": "system.net.http/4.3.0", "hashPath": "system.net.http.4.3.0.nupkg.sha512" }, + "System.Net.NameResolution/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AFYl08R7MrsrEjqpQWTZWBadqXyTzNDaWpMqyxhb0d6sGhV6xMDKueuBXlLL30gz+DIRY6MpdgnHWlCh5wmq9w==", + "path": "system.net.nameresolution/4.3.0", + "hashPath": "system.net.nameresolution.4.3.0.nupkg.sha512" + }, "System.Net.Primitives/4.3.0": { "type": "package", "serviceable": true, @@ -4220,6 +3640,13 @@ "path": "system.private.servicemodel/4.7.0", "hashPath": "system.private.servicemodel.4.7.0.nupkg.sha512" }, + "System.Private.Uri/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-I4SwANiUGho1esj4V4oSlPllXjzCZDE+5XXso2P03LW2vOda2Enzh8DWOxwN6hnrJyp314c7KuVu31QYhRzOGg==", + "path": "system.private.uri/4.3.0", + "hashPath": "system.private.uri.4.3.0.nupkg.sha512" + }, "System.Reflection/4.3.0": { "type": "package", "serviceable": true, @@ -4318,6 +3745,13 @@ "path": "system.runtime.interopservices.runtimeinformation/4.3.0", "hashPath": "system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512" }, + "System.Runtime.Loader/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-DHMaRn8D8YCK2GG2pw+UzNxn/OHVfaWx7OTLBD/hPegHZZgcZh3H6seWegrC4BYwsfuGrywIuT+MQs+rPqRLTQ==", + "path": "system.runtime.loader/4.3.0", + "hashPath": "system.runtime.loader.4.3.0.nupkg.sha512" + }, "System.Runtime.Numerics/4.3.0": { "type": "package", "serviceable": true, @@ -4325,6 +3759,20 @@ "path": "system.runtime.numerics/4.3.0", "hashPath": "system.runtime.numerics.4.3.0.nupkg.sha512" }, + "System.Runtime.Serialization.Formatters/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KT591AkTNFOTbhZlaeMVvfax3RqhH1EJlcwF50Wm7sfnBLuHiOeZRRKrr1ns3NESkM20KPZ5Ol/ueMq5vg4QoQ==", + "path": "system.runtime.serialization.formatters/4.3.0", + "hashPath": "system.runtime.serialization.formatters.4.3.0.nupkg.sha512" + }, + "System.Runtime.Serialization.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Wz+0KOukJGAlXjtKr+5Xpuxf8+c8739RI1C+A2BoQZT+wMCCoMDDdO8/4IRHfaVINqL78GO8dW8G2lW/e45Mcw==", + "path": "system.runtime.serialization.primitives/4.3.0", + "hashPath": "system.runtime.serialization.primitives.4.3.0.nupkg.sha512" + }, "System.Security.AccessControl/4.7.0": { "type": "package", "serviceable": true, @@ -4437,6 +3885,13 @@ "path": "system.text.encoding/4.3.0", "hashPath": "system.text.encoding.4.3.0.nupkg.sha512" }, + "System.Text.Encoding.CodePages/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IRiEFUa5b/Gs5Egg8oqBVoywhtOeaO2KOx3j0RfcYY/raxqBuEK7NXRDgOwtYM8qbi+7S4RPXUbNt+ZxyY0/NQ==", + "path": "system.text.encoding.codepages/4.3.0", + "hashPath": "system.text.encoding.codepages.4.3.0.nupkg.sha512" + }, "System.Text.Encoding.Extensions/4.3.0": { "type": "package", "serviceable": true, @@ -4458,12 +3913,12 @@ "path": "system.text.json/10.0.0", "hashPath": "system.text.json.10.0.0.nupkg.sha512" }, - "System.Text.RegularExpressions/4.3.0": { + "System.Text.RegularExpressions/4.3.1": { "type": "package", "serviceable": true, - "sha512": "sha512-RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==", - "path": "system.text.regularexpressions/4.3.0", - "hashPath": "system.text.regularexpressions.4.3.0.nupkg.sha512" + "sha512": "sha512-N0kNRrWe4+nXOWlpLT4LAY5brb8caNFlUuIRpraCVMDLYutKkol1aV079rQjLuSxKMJT2SpBQsYX9xbcTMmzwg==", + "path": "system.text.regularexpressions/4.3.1", + "hashPath": "system.text.regularexpressions.4.3.1.nupkg.sha512" }, "System.Threading/4.3.0": { "type": "package", @@ -4472,6 +3927,13 @@ "path": "system.threading/4.3.0", "hashPath": "system.threading.4.3.0.nupkg.sha512" }, + "System.Threading.Overlapped/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-m3HQ2dPiX/DSTpf+yJt8B0c+SRvzfqAJKx+QDWi+VLhz8svLT23MVjEOHPF/KiSLeArKU/iHescrbLd3yVgyNg==", + "path": "system.threading.overlapped/4.3.0", + "hashPath": "system.threading.overlapped.4.3.0.nupkg.sha512" + }, "System.Threading.Tasks/4.3.0": { "type": "package", "serviceable": true, @@ -4486,6 +3948,20 @@ "path": "system.threading.tasks.extensions/4.3.0", "hashPath": "system.threading.tasks.extensions.4.3.0.nupkg.sha512" }, + "System.Threading.Thread/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", + "path": "system.threading.thread/4.3.0", + "hashPath": "system.threading.thread.4.3.0.nupkg.sha512" + }, + "System.Threading.ThreadPool/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-k/+g4b7vjdd4aix83sTgC9VG6oXYKAktSfNIJUNGxPEj7ryEOfzHHhfnmsZvjxawwcD9HyWXKCXmPjX8U4zeSw==", + "path": "system.threading.threadpool/4.3.0", + "hashPath": "system.threading.threadpool.4.3.0.nupkg.sha512" + }, "System.Threading.Timer/4.3.0": { "type": "package", "serviceable": true, @@ -4507,6 +3983,13 @@ "path": "system.xml.xdocument/4.3.0", "hashPath": "system.xml.xdocument.4.3.0.nupkg.sha512" }, + "System.Xml.XmlDocument/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lJ8AxvkX7GQxpC6GFCeBj8ThYVyQczx2+f/cWHJU8tjS7YfI6Cv6bon70jVEgs2CiFbmmM8b9j1oZVx0dSI2Ww==", + "path": "system.xml.xmldocument/4.3.0", + "hashPath": "system.xml.xmldocument.4.3.0.nupkg.sha512" + }, "Telerik.UI.for.Wpf.NetCore.Xaml/2024.1.408": { "type": "package", "serviceable": true, @@ -4569,6 +4052,11 @@ "serviceable": false, "sha512": "" }, + "XP.ReportEngine/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, "BR.AN.PviServices/1.1.0.0": { "type": "reference", "serviceable": false, diff --git a/ReleaseFiles/XplorePlane.dll b/ReleaseFiles/XplorePlane.dll index 25a23cf..8f80c5a 100644 Binary files a/ReleaseFiles/XplorePlane.dll and b/ReleaseFiles/XplorePlane.dll differ diff --git a/ReleaseFiles/XplorePlane.dll.config b/ReleaseFiles/XplorePlane.dll.config index 7465d52..7123378 100644 --- a/ReleaseFiles/XplorePlane.dll.config +++ b/ReleaseFiles/XplorePlane.dll.config @@ -7,7 +7,10 @@ - + + + + @@ -122,7 +125,6 @@ - @@ -148,7 +150,7 @@ - + @@ -161,6 +163,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ReleaseFiles/XplorePlane.exe b/ReleaseFiles/XplorePlane.exe index c6c35c7..c60cd80 100644 Binary files a/ReleaseFiles/XplorePlane.exe and b/ReleaseFiles/XplorePlane.exe differ diff --git a/ReleaseFiles/XplorePlane.pdb b/ReleaseFiles/XplorePlane.pdb index e5dbb6b..05fa658 100644 Binary files a/ReleaseFiles/XplorePlane.pdb and b/ReleaseFiles/XplorePlane.pdb differ diff --git a/ReleaseFiles/XplorePlane.runtimeconfig.json b/ReleaseFiles/XplorePlane.runtimeconfig.json index 1dc0145..b2dedf3 100644 --- a/ReleaseFiles/XplorePlane.runtimeconfig.json +++ b/ReleaseFiles/XplorePlane.runtimeconfig.json @@ -12,7 +12,8 @@ } ], "configProperties": { - "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": true + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": true, + "CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false } } } \ No newline at end of file diff --git a/ReleaseFiles/Y.Tracing.Configuration.txt b/ReleaseFiles/Y.Tracing.Configuration.txt new file mode 100644 index 0000000..6b53ce9 --- /dev/null +++ b/ReleaseFiles/Y.Tracing.Configuration.txt @@ -0,0 +1,4 @@ +// Flag, ob die Trace-Meldungen asynchron zu protokolliern sind: 1 fr asynchron, 0 fr synchron. +1 +// Kategorie Konfigurationen: +FXDriver 0 diff --git a/ReleaseFiles/en-US/XP.Camera.resources.dll b/ReleaseFiles/en-US/XP.Camera.resources.dll index 6b54249..0467459 100644 Binary files a/ReleaseFiles/en-US/XP.Camera.resources.dll and b/ReleaseFiles/en-US/XP.Camera.resources.dll differ diff --git a/ReleaseFiles/en-US/XP.Common.resources.dll b/ReleaseFiles/en-US/XP.Common.resources.dll index d7a9c9d..5b2d299 100644 Binary files a/ReleaseFiles/en-US/XP.Common.resources.dll and b/ReleaseFiles/en-US/XP.Common.resources.dll differ diff --git a/ReleaseFiles/en-US/XP.Hardware.Detector.resources.dll b/ReleaseFiles/en-US/XP.Hardware.Detector.resources.dll index bf52a80..27b97b8 100644 Binary files a/ReleaseFiles/en-US/XP.Hardware.Detector.resources.dll and b/ReleaseFiles/en-US/XP.Hardware.Detector.resources.dll differ diff --git a/ReleaseFiles/en-US/XP.Hardware.MotionControl.resources.dll b/ReleaseFiles/en-US/XP.Hardware.MotionControl.resources.dll index 6cb548f..85e1fd4 100644 Binary files a/ReleaseFiles/en-US/XP.Hardware.MotionControl.resources.dll and b/ReleaseFiles/en-US/XP.Hardware.MotionControl.resources.dll differ diff --git a/ReleaseFiles/en-US/XP.Hardware.PLC.resources.dll b/ReleaseFiles/en-US/XP.Hardware.PLC.resources.dll index f84b5a5..facd652 100644 Binary files a/ReleaseFiles/en-US/XP.Hardware.PLC.resources.dll and b/ReleaseFiles/en-US/XP.Hardware.PLC.resources.dll differ diff --git a/ReleaseFiles/en-US/XP.Hardware.RaySource.resources.dll b/ReleaseFiles/en-US/XP.Hardware.RaySource.resources.dll index 8fb508c..78bd8c2 100644 Binary files a/ReleaseFiles/en-US/XP.Hardware.RaySource.resources.dll and b/ReleaseFiles/en-US/XP.Hardware.RaySource.resources.dll differ diff --git a/ReleaseFiles/en-US/XP.ReportEngine.resources.dll b/ReleaseFiles/en-US/XP.ReportEngine.resources.dll new file mode 100644 index 0000000..a525426 Binary files /dev/null and b/ReleaseFiles/en-US/XP.ReportEngine.resources.dll differ diff --git a/ReleaseFiles/itext.barcodes.dll b/ReleaseFiles/itext.barcodes.dll new file mode 100644 index 0000000..00eafd0 Binary files /dev/null and b/ReleaseFiles/itext.barcodes.dll differ diff --git a/ReleaseFiles/itext.bouncy-castle-adapter.dll b/ReleaseFiles/itext.bouncy-castle-adapter.dll new file mode 100644 index 0000000..c665389 Binary files /dev/null and b/ReleaseFiles/itext.bouncy-castle-adapter.dll differ diff --git a/ReleaseFiles/itext.bouncy-castle-connector.dll b/ReleaseFiles/itext.bouncy-castle-connector.dll new file mode 100644 index 0000000..cb4618a Binary files /dev/null and b/ReleaseFiles/itext.bouncy-castle-connector.dll differ diff --git a/ReleaseFiles/itext.commons.dll b/ReleaseFiles/itext.commons.dll new file mode 100644 index 0000000..7e1ac5a Binary files /dev/null and b/ReleaseFiles/itext.commons.dll differ diff --git a/ReleaseFiles/itext.forms.dll b/ReleaseFiles/itext.forms.dll new file mode 100644 index 0000000..6cca33a Binary files /dev/null and b/ReleaseFiles/itext.forms.dll differ diff --git a/ReleaseFiles/itext.io.dll b/ReleaseFiles/itext.io.dll new file mode 100644 index 0000000..816b041 Binary files /dev/null and b/ReleaseFiles/itext.io.dll differ diff --git a/ReleaseFiles/itext.kernel.dll b/ReleaseFiles/itext.kernel.dll new file mode 100644 index 0000000..3cb7dc3 Binary files /dev/null and b/ReleaseFiles/itext.kernel.dll differ diff --git a/ReleaseFiles/itext.layout.dll b/ReleaseFiles/itext.layout.dll new file mode 100644 index 0000000..1e4b6c9 Binary files /dev/null and b/ReleaseFiles/itext.layout.dll differ diff --git a/ReleaseFiles/itext.pdfa.dll b/ReleaseFiles/itext.pdfa.dll new file mode 100644 index 0000000..80d49b2 Binary files /dev/null and b/ReleaseFiles/itext.pdfa.dll differ diff --git a/ReleaseFiles/itext.pdfua.dll b/ReleaseFiles/itext.pdfua.dll new file mode 100644 index 0000000..3fedc4f Binary files /dev/null and b/ReleaseFiles/itext.pdfua.dll differ diff --git a/ReleaseFiles/itext.sign.dll b/ReleaseFiles/itext.sign.dll new file mode 100644 index 0000000..0c7e1cf Binary files /dev/null and b/ReleaseFiles/itext.sign.dll differ diff --git a/ReleaseFiles/itext.styledxmlparser.dll b/ReleaseFiles/itext.styledxmlparser.dll new file mode 100644 index 0000000..7d2a96c Binary files /dev/null and b/ReleaseFiles/itext.styledxmlparser.dll differ diff --git a/ReleaseFiles/itext.svg.dll b/ReleaseFiles/itext.svg.dll new file mode 100644 index 0000000..9ddd289 Binary files /dev/null and b/ReleaseFiles/itext.svg.dll differ diff --git a/ReleaseFiles/zh-CN/XP.Common.resources.dll b/ReleaseFiles/zh-CN/XP.Common.resources.dll index 3a415f1..374d52e 100644 Binary files a/ReleaseFiles/zh-CN/XP.Common.resources.dll and b/ReleaseFiles/zh-CN/XP.Common.resources.dll differ diff --git a/ReleaseFiles/zh-CN/XP.Hardware.Detector.resources.dll b/ReleaseFiles/zh-CN/XP.Hardware.Detector.resources.dll index 773b80e..d714c9c 100644 Binary files a/ReleaseFiles/zh-CN/XP.Hardware.Detector.resources.dll and b/ReleaseFiles/zh-CN/XP.Hardware.Detector.resources.dll differ diff --git a/ReleaseFiles/zh-CN/XP.Hardware.MotionControl.resources.dll b/ReleaseFiles/zh-CN/XP.Hardware.MotionControl.resources.dll index 7219b8b..c18ff74 100644 Binary files a/ReleaseFiles/zh-CN/XP.Hardware.MotionControl.resources.dll and b/ReleaseFiles/zh-CN/XP.Hardware.MotionControl.resources.dll differ diff --git a/ReleaseFiles/zh-CN/XP.Hardware.PLC.resources.dll b/ReleaseFiles/zh-CN/XP.Hardware.PLC.resources.dll index 9c19a09..7f90aa5 100644 Binary files a/ReleaseFiles/zh-CN/XP.Hardware.PLC.resources.dll and b/ReleaseFiles/zh-CN/XP.Hardware.PLC.resources.dll differ diff --git a/ReleaseFiles/zh-CN/XP.Hardware.RaySource.resources.dll b/ReleaseFiles/zh-CN/XP.Hardware.RaySource.resources.dll index 50753d8..648d5a6 100644 Binary files a/ReleaseFiles/zh-CN/XP.Hardware.RaySource.resources.dll and b/ReleaseFiles/zh-CN/XP.Hardware.RaySource.resources.dll differ diff --git a/ReleaseFiles/zh-CN/XP.ImageProcessing.CfgControl.resources.dll b/ReleaseFiles/zh-CN/XP.ImageProcessing.CfgControl.resources.dll index a2bf31a..b7786dd 100644 Binary files a/ReleaseFiles/zh-CN/XP.ImageProcessing.CfgControl.resources.dll and b/ReleaseFiles/zh-CN/XP.ImageProcessing.CfgControl.resources.dll differ diff --git a/ReleaseFiles/zh-CN/XP.ImageProcessing.Processors.resources.dll b/ReleaseFiles/zh-CN/XP.ImageProcessing.Processors.resources.dll index 2321969..6441b5e 100644 Binary files a/ReleaseFiles/zh-CN/XP.ImageProcessing.Processors.resources.dll and b/ReleaseFiles/zh-CN/XP.ImageProcessing.Processors.resources.dll differ diff --git a/ReleaseFiles/zh-CN/XP.ReportEngine.resources.dll b/ReleaseFiles/zh-CN/XP.ReportEngine.resources.dll new file mode 100644 index 0000000..0bfffa6 Binary files /dev/null and b/ReleaseFiles/zh-CN/XP.ReportEngine.resources.dll differ diff --git a/ReleaseFiles/zh-TW/XP.Common.resources.dll b/ReleaseFiles/zh-TW/XP.Common.resources.dll index 3c36a0e..e984f03 100644 Binary files a/ReleaseFiles/zh-TW/XP.Common.resources.dll and b/ReleaseFiles/zh-TW/XP.Common.resources.dll differ diff --git a/ReleaseFiles/zh-TW/XP.Hardware.Detector.resources.dll b/ReleaseFiles/zh-TW/XP.Hardware.Detector.resources.dll index c914527..2e81501 100644 Binary files a/ReleaseFiles/zh-TW/XP.Hardware.Detector.resources.dll and b/ReleaseFiles/zh-TW/XP.Hardware.Detector.resources.dll differ diff --git a/ReleaseFiles/zh-TW/XP.Hardware.MotionControl.resources.dll b/ReleaseFiles/zh-TW/XP.Hardware.MotionControl.resources.dll index 993cae2..a74c4a4 100644 Binary files a/ReleaseFiles/zh-TW/XP.Hardware.MotionControl.resources.dll and b/ReleaseFiles/zh-TW/XP.Hardware.MotionControl.resources.dll differ diff --git a/ReleaseFiles/zh-TW/XP.Hardware.PLC.resources.dll b/ReleaseFiles/zh-TW/XP.Hardware.PLC.resources.dll index 73a659b..1bdde25 100644 Binary files a/ReleaseFiles/zh-TW/XP.Hardware.PLC.resources.dll and b/ReleaseFiles/zh-TW/XP.Hardware.PLC.resources.dll differ diff --git a/ReleaseFiles/zh-TW/XP.Hardware.RaySource.resources.dll b/ReleaseFiles/zh-TW/XP.Hardware.RaySource.resources.dll index ccf0a59..d280028 100644 Binary files a/ReleaseFiles/zh-TW/XP.Hardware.RaySource.resources.dll and b/ReleaseFiles/zh-TW/XP.Hardware.RaySource.resources.dll differ diff --git a/ReleaseFiles/zh-TW/XP.ReportEngine.resources.dll b/ReleaseFiles/zh-TW/XP.ReportEngine.resources.dll new file mode 100644 index 0000000..73fad13 Binary files /dev/null and b/ReleaseFiles/zh-TW/XP.ReportEngine.resources.dll differ diff --git a/XP.Camera/Calibration/CalibrationLocalizedStrings.cs b/XP.Camera/Calibration/CalibrationLocalizedStrings.cs index a914b9c..e165938 100644 --- a/XP.Camera/Calibration/CalibrationLocalizedStrings.cs +++ b/XP.Camera/Calibration/CalibrationLocalizedStrings.cs @@ -1,8 +1,94 @@ -using XP.Camera.Calibration.Resources; +using System.ComponentModel; +using System.Globalization; +using System.Resources; +using System.Runtime.CompilerServices; namespace XP.Camera.Calibration; -public class CalibrationLocalizedStrings +/// +/// 本地化字符串包装类 +/// 使用 XP.Common.Resources.Resources 获取本地化字符串 +/// +public class CalibrationLocalizedStrings : INotifyPropertyChanged { - public CalibrationResources Resources { get; } = new CalibrationResources(); + private static readonly ResourceManager _resourceManager = new( + "XP.Common.Resources.Resources", + typeof(XP.Common.Resources.Resources).Assembly); + + public event PropertyChangedEventHandler? PropertyChanged; + + protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + private string GetString(string key) + { + return _resourceManager.GetString(key, CultureInfo.CurrentUICulture) ?? key; + } + + // 九点标定 + public string CalibrationToolTitle => GetString("CalibrationToolTitle"); + public string CalibrationLoadImage => GetString("CalibrationLoadImage"); + public string CalibrationLoadCsv => GetString("CalibrationLoadCsv"); + public string CalibrationExecute => GetString("CalibrationExecute"); + public string CalibrationSave => GetString("CalibrationSave"); + public string CalibrationLoad => GetString("CalibrationLoad"); + public string CalibrationShowWorld => GetString("CalibrationShowWorld"); + public string CalibrationPointList => GetString("CalibrationPointList"); + public string CalibrationPixelX => GetString("CalibrationPixelX"); + public string CalibrationPixelY => GetString("CalibrationPixelY"); + public string CalibrationWorldX => GetString("CalibrationWorldX"); + public string CalibrationWorldY => GetString("CalibrationWorldY"); + public string CalibrationStatusReady => GetString("CalibrationStatusReady"); + public string CalibrationStatusImageLoaded => GetString("CalibrationStatusImageLoaded"); + public string CalibrationStatusCsvLoaded => GetString("CalibrationStatusCsvLoaded"); + public string CalibrationStatusSuccess => GetString("CalibrationStatusSuccess"); + public string CalibrationStatusFailed => GetString("CalibrationStatusFailed"); + public string CalibrationStatusSaved => GetString("CalibrationStatusSaved"); + public string CalibrationStatusLoaded => GetString("CalibrationStatusLoaded"); + public string CalibrationCoordinates => GetString("CalibrationCoordinates"); + public string CalibrationErrorMinPoints => GetString("CalibrationErrorMinPoints"); + public string CalibrationSuccessTitle => GetString("CalibrationSuccessTitle"); + public string CalibrationSuccessMessage => GetString("CalibrationSuccessMessage"); + public string CalibrationSaveSuccess => GetString("CalibrationSaveSuccess"); + public string CalibrationLoadSuccess => GetString("CalibrationLoadSuccess"); + public string CalibrationLoadFailed => GetString("CalibrationLoadFailed"); + + // 棋盘格标定 + public string ChessboardToolTitle => GetString("ChessboardToolTitle"); + public string ChessboardAddImages => GetString("ChessboardAddImages"); + public string ChessboardClearImages => GetString("ChessboardClearImages"); + public string ChessboardCalibrate => GetString("ChessboardCalibrate"); + public string ChessboardSave => GetString("ChessboardSave"); + public string ChessboardLoad => GetString("ChessboardLoad"); + public string ChessboardUndistort => GetString("ChessboardUndistort"); + public string ChessboardParameters => GetString("ChessboardParameters"); + public string ChessboardWidth => GetString("ChessboardWidth"); + public string ChessboardHeight => GetString("ChessboardHeight"); + public string ChessboardSquareSize => GetString("ChessboardSquareSize"); + public string ChessboardImageList => GetString("ChessboardImageList"); + public string ChessboardStatusInfo => GetString("ChessboardStatusInfo"); + public string ChessboardStatusReady => GetString("ChessboardStatusReady"); + public string ChessboardStatusAdded => GetString("ChessboardStatusAdded"); + public string ChessboardStatusCleared => GetString("ChessboardStatusCleared"); + public string ChessboardStatusCalibrating => GetString("ChessboardStatusCalibrating"); + public string ChessboardStatusSuccess => GetString("ChessboardStatusSuccess"); + public string ChessboardStatusFailed => GetString("ChessboardStatusFailed"); + public string ChessboardStatusSaved => GetString("ChessboardStatusSaved"); + public string ChessboardStatusLoaded => GetString("ChessboardStatusLoaded"); + public string ChessboardStatusUndistorted => GetString("ChessboardStatusUndistorted"); + public string ChessboardStatusImageError => GetString("ChessboardStatusImageError"); + public string ChessboardProgressPreparing => GetString("ChessboardProgressPreparing"); + public string ChessboardProgressDetecting => GetString("ChessboardProgressDetecting"); + public string ChessboardProgressCalibrating => GetString("ChessboardProgressCalibrating"); + public string ChessboardProgressCalculating => GetString("ChessboardProgressCalculating"); + public string ChessboardProgressComplete => GetString("ChessboardProgressComplete"); + public string ChessboardProgressFailed => GetString("ChessboardProgressFailed"); + public string ChessboardErrorMinImages => GetString("ChessboardErrorMinImages"); + public string ChessboardErrorInsufficientValid => GetString("ChessboardErrorInsufficientValid"); + public string ChessboardSaveSuccess => GetString("ChessboardSaveSuccess"); + public string ChessboardLoadSuccess => GetString("ChessboardLoadSuccess"); + public string ChessboardCalibrationComplete => GetString("ChessboardCalibrationComplete"); + public string ChessboardImageError => GetString("ChessboardImageError"); } diff --git a/XP.Camera/Calibration/Controls/CalibrationControl.xaml b/XP.Camera/Calibration/Controls/CalibrationControl.xaml index 7803ebf..9c12e48 100644 --- a/XP.Camera/Calibration/Controls/CalibrationControl.xaml +++ b/XP.Camera/Calibration/Controls/CalibrationControl.xaml @@ -74,32 +74,42 @@ - - - - - - @@ -120,7 +130,7 @@ - @@ -130,13 +140,13 @@ FontFamily="Segoe UI" BorderBrush="{StaticResource BorderColor}" BorderThickness="1"> - - - - @@ -162,4 +172,4 @@ - + \ No newline at end of file diff --git a/XP.Camera/Calibration/Controls/ChessboardCalibrationControl.xaml b/XP.Camera/Calibration/Controls/ChessboardCalibrationControl.xaml index 35a5743..39592b4 100644 --- a/XP.Camera/Calibration/Controls/ChessboardCalibrationControl.xaml +++ b/XP.Camera/Calibration/Controls/ChessboardCalibrationControl.xaml @@ -74,29 +74,41 @@ - - - - - - @@ -117,7 +129,7 @@ - @@ -129,16 +141,16 @@ - + - + - + - @@ -169,7 +181,7 @@ Visibility="{Binding IsCalibrating, Converter={StaticResource BooleanToVisibilityConverter}}" /> - + + + + + + + + + + + + + + + + - + ToolTip="{loc:Localization AC_Save}" + telerik:StyleManager.Theme="Crystal"> + + + + - + ToolTip="{loc:Localization AC_Restore}" + IsEnabled="{Binding HasSavedPositions}" + telerik:StyleManager.Theme="Crystal"> + + + + - - - - - - - + diff --git a/XP.Hardware.MotionControl/Views/AxisControlView.xaml.cs b/XP.Hardware.MotionControl/Views/AxisControlView.xaml.cs index 58a421b..b8fdcf3 100644 --- a/XP.Hardware.MotionControl/Views/AxisControlView.xaml.cs +++ b/XP.Hardware.MotionControl/Views/AxisControlView.xaml.cs @@ -18,6 +18,9 @@ namespace XP.Hardware.MotionControl.Views { InitializeComponent(); + // 监听视图 Loaded 事件,在视图加载时同步联动状态到 PLC | Listen to view Loaded event, sync linkage state to PLC on view load + Loaded += AxisControlView_Loaded; + // 监听摇杆只读依赖属性变化,推送到 ViewModel | Listen to joystick read-only DP changes and push to ViewModel var dualOutputXDesc = DependencyPropertyDescriptor.FromProperty(VirtualJoystick.OutputXProperty, typeof(VirtualJoystick)); var dualOutputYDesc = DependencyPropertyDescriptor.FromProperty(VirtualJoystick.OutputYProperty, typeof(VirtualJoystick)); @@ -230,5 +233,25 @@ namespace XP.Hardware.MotionControl.Views } #endregion + + #region 视图加载事件 | View Loaded Event + + private void AxisControlView_Loaded(object sender, RoutedEventArgs e) + { + // 视图加载时同步联动状态到 PLC | Sync linkage state to PLC when view is loaded + var viewModel = ViewModel; + if (viewModel != null && viewModel.SZDZLock) + { + // 调用服务设置联动 | Call service to set linkage + var result = viewModel.SetSZDZLinkageToPlc(); + if (!result.Success) + { + // 记录日志但不阻塞加载 | Log but don't block loading + viewModel.Logger.Warn("视图加载时同步联动状态失败:{Reason} | Failed to sync linkage state on view load: {Reason}", result.ErrorMessage); + } + } + } + + #endregion } } diff --git a/XP.Hardware.MotionControl/XP.Hardware.MotionControl.csproj b/XP.Hardware.MotionControl/XP.Hardware.MotionControl.csproj index 1519476..740fc18 100644 --- a/XP.Hardware.MotionControl/XP.Hardware.MotionControl.csproj +++ b/XP.Hardware.MotionControl/XP.Hardware.MotionControl.csproj @@ -13,16 +13,29 @@ - - ResXFileCodeGenerator - Resources.Designer.cs - + - - True - True - Resources.resx - + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + diff --git a/XP.Hardware.PLC/ReleaseFiles/PlcAddrDfn.xml b/XP.Hardware.PLC/ReleaseFiles/PlcAddrDfn.xml new file mode 100644 index 0000000..dbe80f2 --- /dev/null +++ b/XP.Hardware.PLC/ReleaseFiles/PlcAddrDfn.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/XP.Hardware.PLC/Services/PlcService.cs b/XP.Hardware.PLC/Services/PlcService.cs index 50d87c3..8f17ccc 100644 --- a/XP.Hardware.PLC/Services/PlcService.cs +++ b/XP.Hardware.PLC/Services/PlcService.cs @@ -179,8 +179,8 @@ namespace XP.Hardware.Plc.Services { StatusText = $"连接异常: {ex.Message} | Connection exception: {ex.Message}"; _logger.Error(ex, $"PLC 初始化失败: {ex.Message} | PLC initialization failed: {ex.Message}"); - MessageBox.Show($"PLC初始化失败 | PLC initialization failed: {ex.Message}", - "错误 | Error", MessageBoxButton.OK, MessageBoxImage.Error); + //MessageBox.Show($"PLC初始化失败 | PLC initialization failed: {ex.Message}", + // "错误 | Error", MessageBoxButton.OK, MessageBoxImage.Error); return false; } catch (Exception ex) diff --git a/XP.Hardware.RaySource/ReleaseFiles/ManiUpdateParams.txt b/XP.Hardware.RaySource/ReleaseFiles/ManiUpdateParams.txt new file mode 100644 index 0000000..f83c69b --- /dev/null +++ b/XP.Hardware.RaySource/ReleaseFiles/ManiUpdateParams.txt @@ -0,0 +1,90 @@ +[sys1____] +"SerialNumber" +[geo_dm__#Cougar] +"Name9" +"Value9" +"Name10" +"Value10" +"Name19" +"Value19" +"Name21" +"Value21" +"Name24" +"Value24" +"Name29" +"Value29" +"Name30" +"Value30" +"Name48" +"Value48" +[geo_dm__#Cheetah] +"Name9" +"Value9" +"Name10" +"Value10" +"Name12" +"Value12" +"Name13" +"Value13" +"Name22" +"Value22" +"Name24" +"Value24" +"Name27" +"Value27" +"Name48" +"Value48" +[joyspeed] +"Speed0" +"Speed1" +"Speed2" +"Speed3" +"Speed4" +"Speed5" +"Speed6" +"Speed7" +"Speed8" +"Speed9" +[loadpos_] +"SafePos[3]" +[para_1__] +"PosSW_End" +"NegSW_End" +"RefPosition" +[para_2__] +"PosSW_End" +"NegSW_End" +"RefPosition" +[para_3__] +"PosSW_End" +"NegSW_End" +"RefPosition" +[para_4__] +"PosSW_End" +"NegSW_End" +"RefPosition" +"RefPositionEnd" +[para_5__] +"PosSW_End" +"NegSW_End" +"RefPosition" +[para_6__] +"PosSW_End" +"NegSW_End" +"RefPosition" +"DistPerTurn" +[para_7__] +"PosSW_End" +"NegSW_End" +"RefPosition" +[para_8__] +"PosSW_End" +"NegSW_End" +"RefPosition" +[para_9__] +"PosSW_End" +"NegSW_End" +"RefPosition" +[dm_door_] +"DoorOpenSwitchAvail#410" +EOF \ No newline at end of file diff --git a/XP.Hardware.RaySource/ReleaseFiles/XRayUpdateParams.txt b/XP.Hardware.RaySource/ReleaseFiles/XRayUpdateParams.txt new file mode 100644 index 0000000..59db549 --- /dev/null +++ b/XP.Hardware.RaySource/ReleaseFiles/XRayUpdateParams.txt @@ -0,0 +1,93 @@ +[MODEDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[TARGETDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[TUBEDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[HSGDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[SYSDM#all] +"everything" +"beginExceptions" +"Version" +"SoftwareVersionPLC" +"SysConfig" +"SoftwareVersion" +"endExceptions" +!************************************************************* +[AMPDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[VACDM#all] +"everything" +"beginExceptions" +"Version_vacuum_system" +"endExceptions" +!************************************************************* +[CENTDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[FOCUSDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[CONSDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[TREGDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[CONDDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[FILDM#all] +"everything" +"beginExceptions" +"Version" +"endExceptions" +!************************************************************* +[TUBEHEADDM#all] +"everything" +"beginExceptions" +"version" +"endExceptions" +!************************************************************* +[INITDM#all] +"everything" +"beginExceptions" +"version" +"endExceptions" +EOF \ No newline at end of file diff --git a/XP.Hardware.RaySource/ReleaseFiles/Y.Tracing.Configuration.txt b/XP.Hardware.RaySource/ReleaseFiles/Y.Tracing.Configuration.txt new file mode 100644 index 0000000..4ff3b14 --- /dev/null +++ b/XP.Hardware.RaySource/ReleaseFiles/Y.Tracing.Configuration.txt @@ -0,0 +1,6 @@ +// Flag, ob die Trace-Meldungen asynchron zu protokolliern sind: 1 fr asynchron, 0 fr synchron. +1 +// Kategorie Konfigurationen: +FXDriver 0 +FXDriverPviXCreateResponse 0 +FXDriverUpgradeCP1483ToCP1583 0 diff --git a/XP.Hardware.RaySource/ReleaseFiles/fx.ini b/XP.Hardware.RaySource/ReleaseFiles/fx.ini new file mode 100644 index 0000000..e9cbc32 --- /dev/null +++ b/XP.Hardware.RaySource/ReleaseFiles/fx.ini @@ -0,0 +1,3907 @@ +;------------------------------------------------------------------------------ +; Help for Control/Value entries +; +; DataType= (FXDataType) +; 0 FX_INT +; 1 FX_LONG +; 2 FX_UINT +; 3 FX_ULONG +; 4 FX_FLOAT +; 5 FX_DOUBLE +; 6 FX_BOOL +; 7 FX_CENTTABLE +; 8 FX_FOCUSTABLE +; 9 FX_STRING +; 10 FX_SHORT +; 11 FX_USHORT +; 12 FX_SCANTABLE +; 13 FX_BYTE +; 14 FX_UBYTE +; 15 FX_TUBECURRENTTABLE +; 16 FX_AXESPOSTABLE +; +; ValueType= (FXValueType) +; 0 FX_ACTVAL +; 1 FX_NOMVAL +; 2 FX_MINVAL +; 3 FX_MAXVAL +; 4 FX_BOOLVAL +; 5 FX_ERRORVAL +; +; Active= +; 0 Variable will not be updated in process image of FXE DLLs +; and can only accessed with explicit read/write +; 1 Variable will be updated in process image of FXE DLLs +; Notify= +; 0: Application notifying will not be used for this variable +; 1: Application notifying will be used for this variable + +;System- und Options-Ids: +;Variablen, die in allen RPS-Konfigurationen vorkommen, erhalten die SysID 1 (FXE_SINGLESTAGE) +;Variablen, die fr spezielle oder optionale RPS-Konfigurationen hinzukommen, z. B. fr Doppelstufen-Rhren, erhalten die +;unten angegebene SysID. (Variablen, die nur fr Doppelstufenrhren verwendet werden, z. B. die SysID 2) +;Wenn Variablen zwei oder mehreren speziellen RPS-Konfigurationen zugeordnet werden mssen, die sich gegenseitig ausschliessen, +;z. B. Para-Variablen fr FOX und TIGER, mssen bei den Variablen die SysID-Eintrge bitweise geoderte Werte sein. Die Variablen der Para-Module +;haben als ID z. B. 24 (0x10 | 0x20) +;FXE_SINGLESTAGE 0x00000001L // Xray-Bit +;FXE_DOUBLESTAGE 0x00000002L // Xray-Bit +;FXE_SCANNING 0x00000004L // Xray-Bit +;SYSTEM_FOX 0x00000008L // Xray-Bit +;SYSTEM_TIGER 0x00000010L // Xray-Bit +;SHUTTEROPTION 0x00000020L // Xray-Bit +;TARGETREGOPTION 0x00000040L // Xray-Bit +;SECONDCENTERING 0x00000080L // Xray-Bit +;FFCOMDRIVER 0x00000100L // Xray-Bit +;AUTOCOND_ENABLED 0x00004000L // Xray-Bit +;MOT_IRIS 0x00000400L // Xray-Bit und Mani-Bit +;FME 0x00000200L // Mani-Bit +;SYSTEM_14 0x00000800L // Mani-Bit CougarFA oder System16 +;SYSTEM_15 0x00001000L // Mani-Bit CougarSMT +;SYSTEM_COUGAR_XL 0x00002000L // Mani-Bit Cheetah +;JOYCTRLOPTION 0x00100000L // Mani-Bit +;------------------------------------------------------------------------------ + +[VarPLCVarHAL_PLCVars] +PLCVarID_0=2274 +PLCVarString_0=LaserCrossHair +PLCVarID_1=2374 +PLCVarString_1=WarnLamp1Ok +PLCVarID_2=2375 +PLCVarString_2=WarnLamp2Ok +PLCVarID_3=2376 +PLCVarString_3=WarnLamp3Ok +PLCVarID_4=2377 +PLCVarString_4=WarnLampDefect + +[XrayHAL] +ReadFromProcessImage=1 +MaxAccVoltageTolerance=1.0 +MaxTubeCurrentTolerance=3.0 +MaxTargetCurrentTolerance=2.0 +EnableXrayOnAfterFlashover=0 + +[ManiHAL] +; Fr die Eigenschaft "Ready" der Schnittstelle IFFAxis wird hier standardmssig +; AxisEnabled && AxisInitialized && !AxisIsNotToControl +; && AxisDriveReady && !AxisDriveError && !AxisError +; verwendet, es wird also NICHT abgefragt, ob die Achse verriegelt ist (AxisModulePresent) +;Default fr AxisReadyBitMask: BitMaskAxisEnabled | BitMaskAxisInitialized | BitMaskAxisDriveReady +;AxisReadyBitMask= +;Default fr AxisNotReadyBitMask: BitMaskAxisIsNotToControl | BitMaskAxisDriveError | BitMaskAxisError +;AxisNotReadyBitMask= +ReadFromProcessImage=1 +; ErrorIfTryingToDriveLockedAxis: 0: Kein Fehler, 1: Fehlermeldung wenn verriegelte Achse versucht wird zu fahren +ErrorIfTryingToDriveLockedAxis=0 +; LoadPosTolerance war vorher in config.prm einstellbar, es wurde aber wahrscheinlich immer Defaultwert 1 verwendet! +LoadPosTolerance=1 + +[ManiSysIDs] +NumSysIDs=3 +SysID_0=8 +SysID_1=16 +SysID_2=4096 + +; FOX +[Detector_8] +TransZ=5 + +[Tube_8] +TransZ= + +[Stage_8] +TransX=0 +TransY=1 +TransZ=2 +RotX=4 +RotY=3 + +; TIGER +[Detector_16] +; Detektor-Kippachse des TIGER kann eigentlich RotX oder RotY sein! +RotX=3 +RotZ=4 + +[Tube_16] +TransZ=2 + +[Stage_16] +TransX=0 +TransY=1 + +;Cougar(SMT) +[Detector_4096] +TransZ=3 +RotY=4 + +[Tube_4096] +TransZ=2 + +[Stage_4096] +TransX=0 +TransY=1 +RotX=5 +RotZ=5 + +[PLCVersionIniFolderNames_CPU0] +V380=V380-389 + +[PLCVersionIniFolderNames_CPU1] +V430=V420-429 + +[PLCVERSIONVARIABLE_0] +DisplayName=SoftwareVersionCPU0 +Descr=SYS_DM.SoftwareVersion +SysID=769 +DataType=3 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +ReadSyncDef=0 + +[PLCVERSIONVARIABLE_1] +DisplayName=SoftwareVersionCPU1 +Descr=sys_dm.SoftwareVersion +SysID=1 +DataType=3 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +ReadSyncDef=0 + +[General] +PLCInitTimeout=120000 +; Nur FXEControl +FXEControlInitTimeout=30000 +; Nur FXEControl +ShowFXEControlWithoutHWLink=0 +UseAFByImg=0 +LoadDetectorDlls=0 +UseScanVariables=0 +UseDbgVariables=1 +UseFXETestVariables=1 +UseALUVariables=0 +FirstSupportedVersion=380 +LastSupportedVersion=430 +; Nur FXEControl: Bezeichnet %-Wert des erreichten Tube-/Targetcurrent vom vorgegebenen (Timer) +TimerCurrentInterruptionThresh=50 +; Nur FXEControl: Bezeichnet %-Wert der erreichten acc. Voltage vom vorgegebenen Wert (Timer) +TimerVoltageInterruptionThresh=70 +; Nur FXEControl: Bezeichnet Dauer der zustzlichen Delaytime in ms zum Start des Timers nach erreichen der anderen Schwellwerte (Timer) +TimerAdditionalDelay=0 +; automatisches Einschalten der Strahlung nach Ueberschlag (de)aktivieren +UseAutoXRayOnAfterFlash=0 +; Datenmodule verbinden? ACHTUNG: Betrifft NICHT Para- und PCPara-Dms fr TIGER und FOX! Diese +; mssen immer verbunden werden, wenn entspr. System vorliegt, sonst funktionieren nicht +; alle Achsen-Funktionen +ConnectDMs=1 +; Variable zur Ueberwachung der RPS (hier: 2014, kVIst) +; Abschalten der Benachrichtigung bei RPS disconnected wenn RPSCheckVariableID <= 0 +RPSCheckVariableID=2014 +; Intervallzeit zur Ueberwachung der RPS in ms +RPSCheckIntervall=10000 +Demoversion=0 +; Kundenversion: 0, Serviceversion: 1, Betriebsversion: 2, Testversion: 3 (Umschalter ASCII-PVI) +AccessVersion=1 +; Apertures wird fr die Amp[1] bis Amp[3] Istwerte (Blendenstrme) verwendet +Apertures=1 +TestFlashOver=0 +DebugMessages=0 +FilIncrement=0.02 +UseDataTypeVerification=1 +; Timeout nach Kaltstart in ms +ColdStartWaitTime=120000 +; 0: no logging 1/2: log errors 3: log errors + show MessageBoxes +LogLevel=2 +; relativer Pfad zum User Manual +UserManualPath=C:\Program Files (x86)\Feinfocus\FXEControl_3.1.1.65\doc\Y.FXE-Control 3.1_v01r00_de_20102585.pdf + +[PLCCommunication] +ModuleEventMask="EV=" +TaskEventMask="EV=" +; 09.11.2004: Gibt an, ob eine Slave-RPS-CPU vorliegen kann (z.Z. nur fuer Nano-FOX) +SlaveCPU=0 +; 09.11.2004: Anzahl RPS-CPUs, maximale Anzahl CPUs ist 2 +CPUCount=1 +; 05.08.2014: Es knnen jetzt die IP und Base der CPUs direkt konfiguriert werden. +; Zudem ist es mglich zwei Rhren anzusteuern. +; Gibt an, ob die Konfigurationen fr HostAdress und HostBase aus der ini verwendet werden sollen, +; oder die hart codierten aus der BRDriverDefs. +UsePLCHostConfig=1 +; Wenn MultipleXrayDevices aktiv ist, dann muss CPUCount auf 1 stehen. Beim Start der FXEControl +; wird ein Abfragedialog geffnet, welche Rhre angezeigt werden soll +MultipleXrayDevices=1 +; Cpu0 muss immer die Adresse einer Rhre sein. +; Die HostAdress entspricht der letzten Stelle der IP-Adresse der Rhre. +Cpu0HostAdress=10 +; Parameter fr den Codierschalter an der PLC. Sollte in der Regel mit der HostAdress gleich sein, +; kann aber auch unterschiedlich konfiguriert werden +Cpu0HostBase=10 +; Beschreibung fr den Auswahldialog beim Start der FXEControl +Cpu0Description=FXT 225.48 - CPU0 192.168.12.10 +; Cpu1 kann die Adresse einer Rhre oder eines Manipulators sein. Wenn nur UsePLCHostConfig und +; CPUCount=2 ausgewhlt ist, dann muss es ein Manipulator sein. +; Die HostAdress entspricht der letzten Stelle der IP adresse der Rhre. +Cpu1HostAdress=11 +; Parameter fr den Codierschalter an der PLC. Sollte in der Regel mit der HostAdress gleich sein, +; kann aber auch unterschiedlich konfiguriert werden. +Cpu1HostBase=11 +; Beschreibung fr den Auswahldialog, der beim Start der FXEControl zur Auswahl der Rhre angezeigt wird. +Cpu1Description=FXT 190.61 - CPU1 192.168.12.11 + +[FFCom] +;FFCOMDRIVER 256 +;ONLY_FFCOMDRIVER 257 +FFComSysID=0 +;FFComSysID=256 +InBufLength=256 +OutBufLength=256 +IDBufLength=4 +FloatPrecision=4 +WaitTimeout=500 +;WaitTimeout=4000 +; Timeouts nicht mehr direkt parametrisierbar, da abh. von RPS-Zykluszeit! +; Dafr kann jetzt hier die verwendete RPS-Zykluszeit angegeben werden! +PLCCycleTime=100 +SwitchFMEToFFComID=3501 +; Thread-Prioritten: 0: normal, 1: above normal, 2: highest, 15: "real time" +; -1: below normal, -2: lowest, -15: idle +ReadThreadPriority=2 +RequestThreadPriority=1 +AutoUpdThreadPriority=1 +LogComm=0 +LogRead=0 +LogWrite=0 +LogAutoUpd=0 +;RTS_CONTROL_DISABLE 0 +;RTS_CONTROL_ENABLE 1 +;RTS_CONTROL_HANDSHAKE 2 +;RTS_CONTROL_TOGGLE 3 +RTSMode=0 +UseCTSHandshake=0 + +[XRayConstants] +BitMaskBattery=2 +BitMaskWarmupDone=4 +BitMaskFilAdjDone=8 +BitMaskAutocentReady=16 +BitMaskAutocentBeamSearch=32 +BitMaskAutocentBeamFound=64 +BitMaskStartupDone=512 +BitMaskAutofuncRuns=1024 +BitMaskInterlockOn=2048 +BitMaskHSGOk=4096 +BitMaskVacuumOk=8192 +BitMaskAutocentRuns=16384 +BitMaskFilAdjRuns=32768 +BitMaskWarmupRuns=65536 +BitMaskStartupRuns=131072 +BitMaskXRayOn=262144 +BitMaskReadyForXRayOn=524288 +BitMaskXRayError=1048576 + +[ManiConstants] +AxesEnableBackside=1 +; Wenn RPS V.2.0 fuer FOX verwendet wird, PositionTolerance=0 setzen, ansonsten 5-10 +; theoretisch kann PositionTolerance fuer FOX auch bei alter RPS 0 gesetzt werden, das einzige +; Problem ist BASIC-Acknowledge der FGUI, da PVI u.U. die nderungen der Ist-Pos. nicht mitbekommt +PositionTolerance=1 +; Wenn RPS V.2.0 fuer FOX verwendet wird, UseManInPosForFOXBasicAckn=1 setzen, ansonsten 0 +; beim Cougar15 und TIGER mit RPS >= 2.6 gibt es die ManiInPos-Variable wieder nicht mehr, +; daher dort auch Positionsvergleich machen! +UseManInPosForFOXBasicAckn=0 +BitMaskAxisError=1 +BitMaskAxisEnabled=2 +BitMaskAxisInitialized=4 +BitMaskAxisReferenced=8 +BitMaskAxisRefMoving=16 +BitMaskAxisMoving=32 +BitMaskAxisDriveReady=64 +BitMaskAxisDriveError=128 +BitMaskAxisPosHWEnd=256 +BitMaskAxisRefHWEnd=512 +BitMaskAxisNegHWEnd=1024 +BitMaskAxisTriggerInput=2048 +BitMaskAxisModulePresent=4096 +BitMaskAxisInPosition=8192 +BitMaskAxisIsNotToControl=16384 +BitMaskAxisIsVirtual=32768 +; Bitmasken fr Manipulator-Statuswort: +; 12.09.2005: Es ist z.Z. vllig unklar, was wie ab welcher RPS-Version +; definiert ist! Was sind die Unterschiede zwischen TIGER mit RPS-Version 2.6 +; und Cougar15 mit Version 2.6, der eigentlich Version 2.7 haben sollte? +BitMaskManiError=1 +BitMaskManiInitialized=4 +BitMaskManiReferenced=8 +BitMaskManiRefMoving=16 +BitMaskManiMoving=32 +BitMaskManiSingleAxisActive=64 +BitMaskManiAllAxesActive=128 +BitMaskManiNonPLCDriveDisabled=256 +BitMaskManiInLoadPos=512 +BitMaskManiLoadPosMoving=33554432 +BitMaskManiInPosition=8192 +BitMaskManiCPSStop=32768 + +[MESSLOG] +EnableAllConnectionsForTest=0 +MessLogTableFileIdx=52 +MinIntervallTime=100 +MinChangeIntervall=200 + +[CONDITIONING] +; Anz. Messpunkte fr berschlge; Messintervall [min] ergibt sich aus ConditTime / ConditTableSize +ConditTableSize=72 +;Einheit: min. Wenn die Zeit zwischen 2 berschlgen > diesen Wert ist, wird die Kond. von der RPS beendet +ConditIntervall=360 +;Einheit: min. Nach max. dieser Zeit wird die Konditionierung beendet +ConditTimeout=3600 +; Max. Anz. Ueberschlaege, bevor Konditionierung (vom PC durch X-Ray off) abgebrochen wird +MaxConditBreaks=250 +;Wartezeit nach Ueberschlag, nach der das Vakuum registriert wird [s] +WaitAfterBreakTime=5 + +[WOBBELING] +;Default-Werte fuers wobbeln +Step=10.0 +Hub=30.0 + +[POSITIONINGTABLE] +; fuer Cougar15: +Description=g_tManiCtrlStartOld.tAxis +ConnectParams="EV= VT=struct VL=0 AL=4" +SysID=4376 + +;LINK_ALL_START_POSITION( _T( "EV=ed VT=struct {. VT=u8 } {. VT=struct VN=11 } {.. VT=f32 } {.. VT=i32 } {.. VT=u8 }" )), +;LINK_ALL_START_SPEED( _T( "EV=ed VT=struct {. VT=u8 } {. VT=struct VN=11 } {.. VT=f32 } {.. VT=i16 } {.. VT=u8 }" )); + +[MOVEAXESSTRUCT] +; fuer Cougar15: +Description=g_tManiCtrlStartOld +;Das Verhalten von PVI ist hier etwas seltsam: Wird die Typinfo der Achsenstruktur ausgelesen, bekommt man immer die VL=112 +;und ein Alignment von 2, auch wenn im Connect-String 4 angegeben wird und auch die Strukturen mit #pragma pack( push, 4) +;definiert werden (eigentlich kommt dann als Variablenlnge 136 raus). Es funktioniert auch alles fehlerfrei, wenn VL=0 angegeben wird! +ConnectParams="EV= VT=struct VL=0 AL=4" +;ConnectParams="EV= VT=struct VL=112 AL=4" +;gendert 03.02.2004: Fahrbefehl jetzt synchron senden! +WriteSyncDef=1 +SysID=4376 + +[MANUALMOVEAXESSTRUCT] +; fuer Cougar15: +Description=g_tManiCtrlManuellOld +ConnectParams="EV= VT=struct VL=0 AL=4" +;gendert 03.02.2004: Fahrbefehl jetzt synchron senden! +WriteSyncDef=1 +SysID=4368 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// erweiterte Control-Variablen +;//////////////////////////////////////////////////////////////////////////////////////// +;condit wait. Nur explizit lesen (?!) +[CONTROLVALUE_253] +Descr=tCONwait +DataType=3 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=-1 +DisplayName=MaxTimeBetweenBreakdowns[ms] +WriteSyncDef=0 +ReadSyncDef=0 + +;Max. Spg. f. Konditionierung. Nur explizit lesen ! +[CONTROLVALUE_254] +Descr=ConditioningData.condCycle[1].kVmax +DataType=4 +ValueType=3 +SysID=1 +Active=0 +Notify=0 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=ConditVoltageMax[kV] +ReadSyncDef=0 + +;Max. Strom f. Konditionierung. Nur explizit lesen ! +[CONTROLVALUE_255] +Descr=ConditioningData.condCycle[1].current_uA +DataType=4 +ValueType=3 +SysID=1 +Active=0 +Notify=0 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=ConditCurrentMax[A] +ReadSyncDef=0 + +[CONTROLVALUE_256] +Descr=HSG.FILwork +DataType=4 +ValueType=1 +;wird nur noch fr alten Tiger (RPS < 2.6) bentigt ! +SysID=0 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=1200 +DisplayName=FilWorkCurrent[A] + +[CONTROLVALUE_257] +Descr=I_fil +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=1200 +DisplayName=FilWorkArray[A] +DataLen=10 + +; Auswahl fuer zu aktualisierendes amp-DM +[CONTROLVALUE_258] +Descr=amp_modul +DataType=10 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +DisplayName=AmpDMRefreshSel + +; Auswahl fuer zu aktualisierendes cent-DM +[CONTROLVALUE_259] +Descr=PC_stat.u16_CENT_DM_nr +DataType=10 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +DisplayName=CentDMRefreshSel + +[CONTROLVALUE_260] +Descr=Sys.Watchdog_enable +DataType=10 +ValueType=1 +SysID=513 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +DisplayName=WatchdogEnable[short] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_261] +Descr=PLC_stat.bo_Watchdog +DataType=6 +ValueType=1 +SysID=513 +;24.06.2003: Watchdog ausgeschaltet wegen Fehler auf RPS! Hoher Laufzeitverbrauch dadurch, +; dass Signal von RPS immer sofort wieder auf 1 zurckgesetzt wurde, nachdem in FXDrivers +; 0 geschickt wurde! +; 13.07.06: Wieder aktiviert, obwohl auf RPS immer noch nicht verbessert +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DisplayName=WatchdogSignal[bool] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_262] +Descr=SYS_DM.seriennum +SysID=1 +DataType=9 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +DataLen=16 +DisplayName=SerialNumber +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_263] +Descr=SystemSettings.u32_workingminute_system +DataType=3 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=SystemCounter + +[CONTROLVALUE_264] +Descr=SystemSettings.u32_workingminute_tube +DataType=3 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=TubeCounter + +[CONTROLVALUE_265] +Descr=SystemSettings.u32_workingminute_filament +DataType=3 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=FilamentCounter + +[CONTROLVALUE_266] +Descr=Condensor.Pmicro +DataType=4 +ValueType=0 +SysID=2 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=700 +DisplayName=ConsModeMicroThrPow[W] +ReadSyncDef=0 + +[CONTROLVALUE_267] +Descr=Condensor.Pnano +DataType=4 +ValueType=0 +SysID=2 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=700 +DisplayName=ConsModeNanoThrPow[W] +ReadSyncDef=0 + +[CONTROLVALUE_268] +Descr=PLC_cmd.reload_MODE_DM +DataType=6 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=ModeChanged[bool] +WriteSyncDef=1 +ReadSyncDef=0 + +[CONTROLVALUE_269] +Descr=PLC_cmd.reload_TARGET_DM +DataType=6 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=TargetChanged[bool] +WriteSyncDef=1 +ReadSyncDef=0 + +[CONTROLVALUE_270] +DisplayName=SoftwareVersion +Descr=SYS_DM.SoftwareVersion +SysID=769 +DataType=3 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +ReadSyncDef=1 + +[CONTROLVALUE_271] +DisplayName=CoilOff +Descr=Sys.coil_off +SysID=1 +DataType=10 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_272] +DisplayName=FilAdjBaseCurrentNew +Descr=PLC_stat.r32_newFilamentCurrentBase +SysID=1 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.05 +RefreshTime=800 + +[CONTROLVALUE_273] +DisplayName=FilAdjBaseCurrentDiff +Descr=PLC_stat.r32_diffToFilamentCurrentBase +SysID=1 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.05 +RefreshTime=800 + +[CONTROLVALUE_274] +DisplayName=PositioningLaser +Descr=Do_Laser +;nd. 14.09.2004: Fuer TIGER, FOX, 15er und 16er! NICHT generell auf FXE! +SysID=6168 +DataType=6 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1200 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_275] +Descr=zoom +SysID=1 +DataType=10 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=BVZoomLevel +WriteSyncDef=0 +ReadSyncDef=0 + +; 07.07.03: Reload-Variablen jetzt Control-Values, vorher ControlCommands +; Hintergrund: 1-0 bergnge dieser Variablen knnen als Signal dafr +; genommen werden, dass die neuen Werte tatschlich in die RPS-Variablenstrukturen +; eingetragen wurden! +[CONTROLVALUE_280] +Descr=PC_cmd.TUBE_DM.read +SysID=513 +DisplayName=ReloadTubeDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_281] +Descr=PC_cmd.AMP_DM.read +SysID=1 +DisplayName=ReloadAmpDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_282] +Descr=PC_cmd.HSG_DM.read +SysID=513 +DisplayName=ReloadHSGDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_283] +Descr=PC_cmd.VAC_DM.read +SysID=1 +DisplayName=ReloadVacuumDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_284] +Descr=PC_cmd.COND_DM.read +SysID=1 +DisplayName=ReloadConditDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_285] +Descr=PC_cmd.SYS_DM.read +SysID=513 +DisplayName=ReloadSystemDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_286] +Descr=PC_cmd.FOCUS_DM.read +SysID=1 +DisplayName=ReloadFocusDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_287] +Descr=PC_cmd.CONS_DM.read +SysID=2 +DisplayName=ReloadCondensorDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_288] +Descr=cmd_read_shutter +SysID=32 +DisplayName=ReloadShutterDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_289] +Descr=PC_cmd.CENT_DM.read +SysID=1 +DisplayName=ReloadCenteringDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_290] +Descr=cmd_read_scan +SysID=4 +DisplayName=ReloadScanDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_291] +Descr=PC_cmd.TIREG_DM.read +SysID=1 +DisplayName=ReloadTiRegDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_292] +Descr=cmd_read_comconf +DisplayName=ReloadComConfDM +;22.11.2004: zunchst ausgeschaltet, bei nchster Version, wenn alle Systeme COMCONF-DM beinhalten, einbauen +SysID=0 +;SysID=513 +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_293] +Descr=PC_cmd.INIT_DM +SysID=1 +DisplayName=ReloadInitDM +DataType=9 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DataLen=10 + +[CONTROLVALUE_294] +DisplayName=ReloadAllDMs +Descr=PC_cmd.ALL_DM.read +SysID=1 +DataType=14 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_295] +DisplayName=UsageAmp1 +Descr=Amp[1].Verwendung +SysID=1 +DataType=9 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +DataLen=16 + +[CONTROLVALUE_296] +DisplayName=UsageAmp2 +Descr=Amp[2].Verwendung +SysID=34 +DataType=9 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +DataLen=16 + +[CONTROLVALUE_297] +DisplayName=UsageAmp3 +Descr=Amp[3].Verwendung +SysID=34 +DataType=9 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +DataLen=16 + +[CONTROLVALUE_298] +DisplayName=DiTubeheadEnable +Descr=Di_tubehead_enable +SysID=1 +DataType=6 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=0 + +[CONTROLVALUE_299] +Descr=target.current_target_number +DataType=11 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=Target +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_300] +Descr=target.last_target_number +DataType=11 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=TargetCount +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_301] +DisplayName=TubeheadNumber +Descr=Tubehead.current_tubehead_number +SysID=1 +DataType=11 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 + +[CONTROLVALUE_302] +DisplayName=TubeheadCount +Descr=Tubehead.last_tubehead_number +SysID=1 +DataType=11 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_303] +Descr=PLC_cmd.reload_TARGET_DM +DataType=6 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=TubeheadChanged[bool] +WriteSyncDef=1 +ReadSyncDef=0 + +[CONTROLVALUE_304] +Descr=iIrisMoveDir +DataType=0 +ValueType=1 +SysID=1024 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=IrisMoveDir + +[CONTROLVALUE_305] +Descr=iIrisSetPos +DataType=0 +ValueType=1 +SysID=1024 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=IrisSetPos + +[CONTROLVALUE_306] +Descr=iIrisCurPos +DataType=0 +ValueType=0 +SysID=1024 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=IrisCurPos + +[CONTROLVALUE_307] +Descr=iIrisCurPosActual +DataType=10 +ValueType=0 +SysID=1024 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=IrisCurPosActual + +[CONTROLVALUE_308] +Descr=Vacon +DataType=6 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=VacuumOn[bool] + +[CONTROLVALUE_309] +Descr=EnableShutterOnIfManiMoves +DataType=6 +ValueType=1 +SysID=32 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 +DisplayName=EnableShutterOnIfManiMoves[bool] + +[CONTROLVALUE_310] +DisplayName=SoftwareVersionMani +Descr=sys_dm.SoftwareVersion +SysID=4120 +DataType=3 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +ReadSyncDef=1 + +[CONTROLVALUE_311] +DisplayName=DetectorXRange +Descr=DetectorXRangeNotDefinedYet +SysID=0 +DataType=3 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +ReadSyncDef=1 + +[CONTROLVALUE_312] +DisplayName=DetectorYRange +Descr=DetectorXRangeNotDefinedYet +SysID=0 +DataType=3 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +ReadSyncDef=1 + +[CONTROLVALUE_313] +DisplayName=AxisCountReal +Descr=g_tManiParameters.uMaxAxesReal +SysID=4096 +DataType=11 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +ReadSyncDef=0 + +[CONTROLVALUE_314] +DisplayName=FocusDetectorDist0 +Descr=FocusDetectorDist0NotDefinedYet +SysID=0 +DataType=3 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +ReadSyncDef=0 + +[CONTROLVALUE_315] +Descr=PC_cmd.FIL_DM.read +SysID=1 +DisplayName=ReloadFilDM +DataType=6 +ValueType=1 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_316] +DisplayName=TrayOffset +Descr=g_fTrayOffset +TaskName=manimove +DataType=4 +ValueType=1 +SysID=4112 +Active=1 +Notify=1 +RefreshTime=10000 +Hysterese=0.1 + +[CONTROLVALUE_317] +DisplayName=Magnification +Descr=g_fMagnification +TaskName=manimove +DataType=4 +ValueType=0 +SysID=4112 +Active=1 +Notify=1 +RefreshTime=250 +Hysterese=0.1 + +[CONTROLVALUE_318] +DisplayName=DoorVersion +Descr=g_tDoor.dwDoorVersion +DataType=2 +ValueType=1 +SysID=4112 +Active=1 +Notify=0 +RefreshTime=2500 +Hysterese=0 + +[CONTROLVALUE_319] +DisplayName=FNCProgramRunning +Descr=g_bFNC_Drive +DataType=6 +ValueType=1 +SysID=4112 +; 20.05.08: Active, Notify=1 (fr Mani-HAL) +Active=1 +Notify=1 +RefreshTime=2500 +Hysterese=0 + +[CONTROLVALUE_320] +DisplayName=EnableAIM +Descr=g_bPC_AIM_Enable +DataType=6 +ValueType=1 +;27.01.06: Auch fuer TIGER, da Aim dort jetzt auch auf RPS +SysID=4112 +; 20.05.08: Active, Notify=1 (fr Mani-HAL) +Active=1 +Notify=1 +RefreshTime=2500 +Hysterese=0 + +[CONTROLVALUE_321] +DisplayName=TeachNewPOI +Descr=l_bXYJoystickDriveOff +TaskName=joyctrl +DataType=6 +ValueType=0 +SysID=16 +Active=1 +Notify=1 +RefreshTime=150 +Hysterese=0 + +[CONTROLVALUE_322] +DisplayName=CamAxisAttachedToRotAxis +Descr=g_tCameraAxis.dwEnable +TaskName= +DataType=3 +ValueType=1 +SysID=16 +Active=1 +Notify=1 +RefreshTime=250 +Hysterese=0 + +[CONTROLVALUE_333] +Descr=l_ptDpr.bSampleHolder +DataType=6 +ValueType=0 +SysID=4096 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=200 +DisplayName=SampleHolderPresent[bool] +WriteSyncDef=1 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_334] +Descr=l_ptDpr.bTurnTable +DataType=6 +ValueType=0 +SysID=4096 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=200 +DisplayName=TurnTablePresent[bool] +WriteSyncDef=1 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_335] +Descr=g_tAIM_Mask.settings +SysID=4120 +DisplayName=AIMSettings +DataType=3 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_336] +Descr=l_bCollProt_Activ +SysID=4096 +DisplayName=CPS_Active +DataType=6 +ValueType=0 +Active=1 +Notify=1 +RefreshTime=500 +TaskName=manimove +Hysterese=0 + +[CONTROLVALUE_337] +Descr=g_bCollProtExists +SysID=4120 +DisplayName=CPS_Exists +DataType=6 +ValueType=0 +Active=1 +Notify=1 +RefreshTime=-1 +Hysterese=0 + +[CONTROLVALUE_338] +Descr=g_bPC_CollProt_Enable +SysID=4120 +DisplayName=CPS_Enabled +DataType=6 +ValueType=1 +Active=1 +Notify=1 +; 13.05.08: RefreshTime wegen Mani-HAL gendert von -1 auf 1000 +RefreshTime=1000 +Hysterese=0 + +[CONTROLVALUE_339] +Descr=g_bPC_PLCinitialized +SysID=4120 +DisplayName=PLC_Initialized +DataType=6 +ValueType=0 +Active=0 +Notify=0 +RefreshTime=-1 +Hysterese=0 + +[CONTROLVALUE_340] +Descr=l_ptDpr.atAxisValues[0].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis1 +TaskName=pp_mast + +[CONTROLVALUE_341] +Descr=l_ptDpr.atAxisValues[1].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis2 +TaskName=pp_mast + +[CONTROLVALUE_342] +Descr=l_ptDpr.atAxisValues[2].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis3 +TaskName=pp_mast + +[CONTROLVALUE_343] +Descr=l_ptDpr.atAxisValues[3].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis4 +TaskName=pp_mast + +[CONTROLVALUE_344] +Descr=l_ptDpr.atAxisValues[4].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis5 +TaskName=pp_mast + +[CONTROLVALUE_345] +Descr=l_ptDpr.atAxisValues[5].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=pp_mast +SysID=4112 +DisplayName=ConfigAxis6 + +[CONTROLVALUE_346] +Descr=l_ptDpr.atAxisValues[6].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis7 +TaskName=pp_mast + +[CONTROLVALUE_347] +Descr=l_ptDpr.atAxisValues[7].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis8 +TaskName=pp_mast + +[CONTROLVALUE_348] +Descr=l_ptDpr.atAxisValues[8].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis9 +TaskName=pp_mast + +[CONTROLVALUE_349] +Descr=l_ptDpr.atAxisValues[9].tAxisParameter.dwAxisConfig +DataType=3 +ValueType=0 +SysID=4112 +Active=1 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=ConfigAxis10 +TaskName=pp_mast + +[CONTROLVALUE_350] +Descr=g_tRelJoy.dwDirSwitch +DisplayName=JoystickXYInverse +DataType=3 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_351] +Descr=g_tRelJoy.dwEnable +DisplayName=XYJoyDependOnRotEnable +DataType=3 +ValueType=1 +SysID=16 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_352] +Descr=g_bServiceMode +DisplayName=ManiServiceMode +DataType=6 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_356] +DisplayName=ACT_AxisPresent +Descr=l_ptDpr.bACTHolder +SysID=4096 +DataType=6 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +TaskName=pp_mast + +[CONTROLVALUE_358] +Descr=g_abEndlessRotDisabled +DataType=6 +ValueType=1 +SysID=4096 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1500 +;10 Achsen +DataLen=10 +DisplayName=EndlessRotDisabledArray[bool] + +;//////////////////////////////////////////////////////////////////////////////////////// +;// Ampel-Variablen +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_359] +DisplayName=Wlamp1DemandState[0] +Descr=l_tLampCmdInterface[0].cDemandState +DataType=14 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_360] +DisplayName=Wlamp1FlashPeriod[0] +Descr=l_tLampCmdInterface[0].wFlashPeriod +DataType=11 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_361] +DisplayName=Wlamp1Set[0] +Descr=l_tLampCmdInterface[0].bSetLamp +DataType=6 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_362] +DisplayName=Wlamp1DemandState[1] +Descr=l_tLampCmdInterface[1].cDemandState +DataType=14 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_363] +DisplayName=Wlamp1FlashPeriod[1] +Descr=l_tLampCmdInterface[1].wFlashPeriod +DataType=11 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_364] +DisplayName=Wlamp1Set[1] +Descr=l_tLampCmdInterface[1].bSetLamp +DataType=6 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_365] +DisplayName=Wlamp1DemandState[2] +Descr=l_tLampCmdInterface[2].cDemandState +DataType=14 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_366] +DisplayName=Wlamp1FlashPeriod[2] +Descr=l_tLampCmdInterface[2].wFlashPeriod +DataType=11 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_367] +DisplayName=Wlamp1Set[2] +Descr=l_tLampCmdInterface[2].bSetLamp +DataType=6 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_368] +DisplayName=Wlamp1DemandState[3] +Descr=l_tLampCmdInterface[3].cDemandState +DataType=14 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_369] +DisplayName=Wlamp1FlashPeriod[3] +Descr=l_tLampCmdInterface[3].wFlashPeriod +DataType=11 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_370] +DisplayName=Wlamp1Set[3] +Descr=l_tLampCmdInterface[3].bSetLamp +DataType=6 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_371] +DisplayName=Wlamp1DemandState[4] +Descr=l_tLampCmdInterface[4].cDemandState +DataType=14 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_372] +DisplayName=Wlamp1FlashPeriod[4] +Descr=l_tLampCmdInterface[4].wFlashPeriod +DataType=11 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +[CONTROLVALUE_373] +DisplayName=Wlamp1Set[4] +Descr=l_tLampCmdInterface[4].bSetLamp +DataType=6 +ValueType=1 +SysID=4112 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +TaskName=sigtower + +;//////////////////////////////////////////////////////////////////////////////////////// +;// Warnlampen-Variablen +;//////////////////////////////////////////////////////////////////////////////////////// +;// Die Variablen fr die einzelnen Warnlampen sind unbrauchbar, +;// immer auf 0 oder nur sehr kurzfristig 1 wenn Fehler +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_374] +DisplayName=WarnlampDefect +Descr=Lamp_def +DataType=6 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 + +[CONTROLVALUE_375] +DisplayName=ManiInterlock +Descr=l_ptDpr.bInterlock +DataType=6 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_376] +Descr=VAC_DM.version +DataType=11 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 +DisplayName=VacuumVersion +ReadSyncDef=0 + +[CONTROLVALUE_377] +Descr=Vac.mess +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.2 +RefreshTime=1000 +DisplayName=VacuumNom[V] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_378] +Descr=HSG.Gridist +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 +DisplayName=GridVoltage[V] +ReadSyncDef=0 + +; nur explizit Lesen fr Autocond. +[CONTROLVALUE_379] +Descr=TUBE_DM.seriennum +DataType=9 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=SerialNumber +ReadSyncDef=0 +DataLen=16 + +[CONTROLVALUE_380] +Descr=TUBE_DM.name +DataType=9 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=1000 +DisplayName=Name +ReadSyncDef=0 +DataLen=16 + +[CONTROLVALUE_381] +Descr=Focus.f +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 +DisplayName=FocusCurAct +ReadSyncDef=0 + +[CONTROLVALUE_382] +Descr=PC_cmd.i32_XrayTimer_set_time +DataType=3 +ValueType=1 +SysID=769 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 +DisplayName=XrayTimer_set_time +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_383] +Descr=PLC_stat.i32_XrayTimer_left_time +DataType=3 +ValueType=1 +SysID=769 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 +DisplayName=XrayTimer_left_time +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_384] +Descr=PLC_stat.u32_cond_character +DataType=0 +ValueType=1 +SysID=769 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=AutoCondenserStatus +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_385] +Descr=PLC_stat.u32_filamentcorradjust +DataType=0 +ValueType=1 +SysID=769 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=FilamentCorrectionTestStatus +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_386] +Descr=r32_calcFilCorr +DataType=4 +ValueType=1 +SysID=769 +Active=1 +Hysterese=0 +RefreshTime=0 +DisplayName=FilamentCorrectionTestResult +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=filcorradj + +[CONTROLVALUE_387] +Descr=PLC_stat.u32_Leckstromtest +DataType=0 +ValueType=1 +SysID=769 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=LeakageCurrentTestStatus +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_388] +Descr=r32_mAist_Mittel +DataType=4 +ValueType=1 +SysID=769 +Active=1 +Hysterese=0 +RefreshTime=0 +DisplayName=LeakageCurrentTestResultMean +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=Leckstrom + +[CONTROLVALUE_389] +Descr=r32_kV_limit_no_leak +DataType=4 +ValueType=1 +SysID=769 +Active=1 +Hysterese=0 +RefreshTime=0 +DisplayName=LeakageCurrentTestResultLimitNoLeak +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=Leckstrom + +[CONTROLVALUE_390] +Descr=bo_leak_is_linear +DataType=6 +ValueType=1 +SysID=769 +Active=1 +Hysterese=0 +RefreshTime=0 +DisplayName=LeakageCurrentTestResultLeakIsLinear +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=Leckstrom + +;//////////////////////////////////////////////////////////////////////////////////////// +;// NEUE VARIABLEN-PARAMETRISIERUNGEN HIER EINTRAGEN +;//////////////////////////////////////////////////////////////////////////////////////// +; Variable zur Zuordnung der Variablen zu verschiedenen FXE-Typen und Systemen. +; Nicht bentigte bzw. nicht auf der RPS vorhandene Variablen werden nicht ber PVI connected +; Die Identifikation ist in dem String bitcodiert +;//////////////////////////////////////////////////////////////////////////////////////// +[SYSTEMID_0] +DisplayName=SysIDVariable1 +Descr=Sys.SysConfig +SysID=769 +DataType=3 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +ReadSyncDef=0 + +[SYSTEMID_1] +DisplayName=SysIDVariable2 +Descr=sys_dm.SysConfig +SysID=1 +DataType=3 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 +ReadSyncDef=0 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// erweiterte Kommandos +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_96] +Descr=PC_cmd.focusCharacteristic.write_default +SysID=1 +DisplayName=WriteDefFocusTable +WriteSyncDef=0 + +[CONTROLCOMMAND_97] +Descr=PC_cmd.condensorCharacteristic.write_default +SysID=2 +DisplayName=WriteDefCentTable +WriteSyncDef=0 + +[CONTROLCOMMAND_98] +Descr=write_def_shut +SysID=32 +DisplayName=WriteDefShutterTable +WriteSyncDef=0 + +[CONTROLCOMMAND_99] +Descr=PC_cmd.reset_workinghour_system +SysID=1 +DisplayName=DelSystemCounter + +[CONTROLCOMMAND_100] +Descr=PC_cmd.reset_workinghour_tube +SysID=1 +DisplayName=DelTubeCounter + +[CONTROLCOMMAND_101] +Descr=PC_cmd.reset_workinghour_filament +SysID=1 +DisplayName=DelFilamentCounter + +; mode-Datenmodul lesen, analog wie bei Kennlinien +[CONTROLCOMMAND_102] +Descr=PC_cmd.MODE_DM.read +SysID=1 +DisplayName=ReadModeModule +WriteSyncDef=0 + +; target-Datenmodul lesen, analog wie bei Kennlinien +[CONTROLCOMMAND_103] +Descr=PC_cmd.TARGET_DM.read +SysID=1 +DisplayName=ReadTargetModule +WriteSyncDef=0 + +; mode-Datenmodul lesen, analog wie bei Kennlinien +[CONTROLCOMMAND_104] +Descr=PC_cmd.MODE_DM.create_new +SysID=1 +DisplayName=NewModeModule +WriteSyncDef=0 + +; target-Datenmodul lesen, analog wie bei Kennlinien +[CONTROLCOMMAND_105] +Descr=PC_cmd.TARGET_DM.create_new +SysID=1 +DisplayName=NewTargetModule +WriteSyncDef=0 + +[CONTROLCOMMAND_106] +Descr=PC_cmd.new_filament +SysID=1 +DisplayName=NewFilament + +[CONTROLCOMMAND_107] +Descr=PC_cmd.focusCharacteristic.read_default +SysID=1 +DisplayName=LoadDefFocusTable +WriteSyncDef=0 + +[CONTROLCOMMAND_108] +Descr=PC_cmd.condensorCharacteristic.read_default +SysID=2 +DisplayName=LoadDefConsTable +WriteSyncDef=0 + +[CONTROLCOMMAND_109] +Descr=read_def_shut +SysID=32 +DisplayName=LoadDefShutterTable +WriteSyncDef=0 + +[CONTROLCOMMAND_111] +Descr=PC_cmd.TubeCharacteristic.read +SysID=512 +DisplayName=DelTubeCounter + +[CONTROLCOMMAND_112] +Descr=PC_cmd.TubeCharacteristic.write +SysID=512 +DisplayName=DelTubeCounter + +[CONTROLCOMMAND_113] +Descr=PC_cmd.TubeCharacteristic.store_point +SysID=512 +DisplayName=DelTubeCounter + +[CONTROLCOMMAND_114] +Descr=PC_cmd.TubeCharacteristic.delete_point +SysID=512 +DisplayName=DelTubeCounter + +[CONTROLCOMMAND_115] +Descr=PC_cmd.TubeCharacteristic.delete_all_points +SysID=512 +DisplayName=DelTubeCounter + +[CONTROLCOMMAND_116] +Descr=PC_cmd.TubeCharacteristic.read_default +SysID=512 +DisplayName=DelTubeCounter + +[CONTROLCOMMAND_117] +Descr=PC_cmd.TubeCharacteristic.write_default +SysID=512 +DisplayName=DelTubeCounter + +[CONTROLCOMMAND_118] +Descr=PC_cmd.TUBEHEAD_DM.read +SysID=1 +DisplayName=ReadTubheadModule + +[CONTROLCOMMAND_119] +Descr=l_ptDpr.tManiCommands.bStartZentPosAll +SysID=4120 +DisplayName=CenterAllAxes +WriteSyncDef=0 +TaskName=pp_mast + +[CONTROLCOMMAND_120] +Descr=l_ptDpr.tManiCommands.bStartLoadPosAll +SysID=4120 +DisplayName=LoadPosAllAxes +WriteSyncDef=0 +TaskName=pp_mast + +[CONTROLCOMMAND_121] +Descr=cmd_opencom +SysID=0 +DisplayName=OpenFFCom +WriteSyncDef=1 + +[CONTROLCOMMAND_122] +Descr=cmd_closecom +SysID=0 +DisplayName=CloseFFCom +WriteSyncDef=1 + +[CONTROLCOMMAND_124] +DisplayName=PC_cmd.xraytimerON +Descr=PC_cmd.xraytimerON +SysID=1 +WriteSyncDef=0 + +[CONTROLCOMMAND_125] +DisplayName=PC_cmd.xraytimerOFF +Descr=PC_cmd.xraytimerOFF +SysID=1 +WriteSyncDef=0 + +[CONTROLCOMMAND_126] +DisplayName=PC_cmd.xraytimerReset +Descr=PC_cmd.xraytimerReset +SysID=1 +WriteSyncDef=0 + +[CONTROLCOMMAND_127] +Descr=PC_cmd.condensor_character_kV +SysID=257 +DisplayName=DoAutocondenserKV +WriteSyncDef=0 + +[CONTROLCOMMAND_128] +Descr=PC_cmd.condensor_character_singlemod +SysID=257 +DisplayName=DoAutocondenserMod +WriteSyncDef=0 + +[CONTROLCOMMAND_129] +Descr=PC_cmd.condensor_character_multimod +SysID=257 +DisplayName=DoAutocondenserAll +WriteSyncDef=0 + +[CONTROLCOMMAND_130] +Descr=PC_cmd.filamentcorradjust +SysID=257 +DisplayName=DoFilamentCorrectionTest +WriteSyncDef=0 + +[CONTROLCOMMAND_131] +Descr=PC_cmd.leckstromtest +SysID=257 +DisplayName=DoLeakageCurrentTest +WriteSyncDef=0 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// Debug-Variablen +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_10000] +Descr=Filament_Q20 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=250 +DisplayName=FilamentQ20 + +[CONTROLVALUE_10001] +Descr=Filament_Q50 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=250 +DisplayName=FilamentQ50 + +[CONTROLVALUE_10002] +Descr=Filament_Q100 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=250 +DisplayName=FilamentQ100 + +[CONTROLVALUE_10003] +Descr=Filament_Q250 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=250 +DisplayName=FilamentQ250 + +[CONTROLVALUE_10004] +Descr=Filament_Q500 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=250 +DisplayName=FilamentQ500 + +[CONTROLVALUE_10005] +Descr=Filament_Q1000 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=250 +DisplayName=FilamentQ1000 + +[CONTROLVALUE_10006] +Descr=Target_Ws_025 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.25 +RefreshTime=1000 +DisplayName=TargetJ025 + +[CONTROLVALUE_10007] +Descr=Target_Ws_05 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=TargetJ05 + +[CONTROLVALUE_10008] +Descr=Target_Ws_1 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=TargetJ1 + +[CONTROLVALUE_10009] +Descr=Target_Ws_2 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=TargetJ2 + +[CONTROLVALUE_10010] +Descr=Target_Ws_4 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=TargetJ4 + +[CONTROLVALUE_10011] +Descr=Target_Ws_6 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=TargetJ6 + +[CONTROLVALUE_10012] +Descr=Target_Ws_10 +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=TargetJ10 + +[CONTROLVALUE_10013] +Descr=Sys_error +DataType=11 +ValueType=0 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1500 +DataLen=21 +DisplayName=SystemErrorArray + +[CONTROLVALUE_10014] +Descr=HSG_error +DataType=11 +ValueType=0 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1500 +DataLen=21 +DisplayName=HSGErrorArray + +[CONTROLVALUE_10015] +Descr=Tube_error +DataType=11 +ValueType=0 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1500 +DataLen=21 +DisplayName=TubeErrorArray + +[CONTROLVALUE_10016] +Descr=Vac_error +DataType=11 +ValueType=0 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1500 +DataLen=21 +DisplayName=VacuumErrorArray + +[CONTROLVALUE_10017] +Descr=Sys_err_count +DataType=11 +ValueType=0 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=4000 +DisplayName=SysErrorArrayIdx + +[CONTROLVALUE_10018] +Descr=HSG_err_count +DataType=11 +ValueType=0 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=4000 +DisplayName=HSGErrorArrayIdx + +[CONTROLVALUE_10019] +Descr=Tube_err_count +DataType=11 +ValueType=0 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=4000 +DisplayName=TubeErrorArrayIdx + +[CONTROLVALUE_10020] +Descr=Vac_err_count +DataType=11 +ValueType=0 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=4000 +DisplayName=VacuumErrorArrayIdx + +[CONTROLVALUE_10021] +DisplayName=LoadPositionEnable1 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[0].tAxisParameter.dwLoadPos_Enab +SysID=4120 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10022] +DisplayName=LoadPositionEnable2 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[1].tAxisParameter.dwLoadPos_Enab +SysID=4120 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10023] +DisplayName=LoadPositionEnable3 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[2].tAxisParameter.dwLoadPos_Enab +SysID=4120 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10024] +DisplayName=LoadPositionEnable4 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[3].tAxisParameter.dwLoadPos_Enab +SysID=4120 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10025] +DisplayName=LoadPositionEnable5 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[4].tAxisParameter.dwLoadPos_Enab +SysID=4120 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10026] +DisplayName=LoadPositionEnable6 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[5].tAxisParameter.dwLoadPos_Enab +SysID=4120 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSEN 7-10 VORERST NUR FUER COUGAR15! +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_10027] +DisplayName=LoadPositionEnable7 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[6].tAxisParameter.dwLoadPos_Enab +SysID=24 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10028] +DisplayName=LoadPositionEnable8 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[7].tAxisParameter.dwLoadPos_Enab +SysID=24 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10029] +DisplayName=LoadPositionEnable9 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[8].tAxisParameter.dwLoadPos_Enab +SysID=24 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10030] +DisplayName=LoadPositionEnable10 +; fr Cougar15: +Descr=l_ptDpr.atAxisValues[9].tAxisParameter.dwLoadPos_Enab +SysID=24 +DataType=1 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// BELADEPOSITIONEN 1-6 VORERST NUR FUER TIGER! +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_10031] +DisplayName=LoadPosition1 +Descr=l_ptDpr.atAxisValues[0].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10032] +DisplayName=LoadPosition2 +Descr=l_ptDpr.atAxisValues[1].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10033] +DisplayName=LoadPosition3 +Descr=l_ptDpr.atAxisValues[2].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10034] +DisplayName=LoadPosition4 +Descr=l_ptDpr.atAxisValues[3].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10035] +DisplayName=LoadPosition5 +Descr=l_ptDpr.atAxisValues[4].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10036] +DisplayName=LoadPosition6 +Descr=l_ptDpr.atAxisValues[5].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10037] +DisplayName=LoadPosition7 +Descr=l_ptDpr.atAxisValues[6].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10038] +DisplayName=LoadPosition8 +Descr=l_ptDpr.atAxisValues[7].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10039] +DisplayName=LoadPosition9 +Descr=l_ptDpr.atAxisValues[8].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +[CONTROLVALUE_10040] +DisplayName=LoadPosition10 +Descr=l_ptDpr.atAxisValues[9].tAxisParameter.fLoadPos +SysID=4112 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// AxesWatch-Variablen +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_10041] +DisplayName=AxisEncValue[0] +Descr=DC_nEncoder[0] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10042] +DisplayName=AxisEncMastSlaveOffset[0] +Descr=l_anMasterSlaveEncoderOffset[0] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10043] +DisplayName=MasterSlaveDiff[0] +Descr=l_afMasterSlaveDiff[0] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10044] +DisplayName=MasterSlaveDiffMax[0] +Descr=l_afMasterSlaveDiffMax[0] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10045] +DisplayName=MastSlavRefMaxDiff[0] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[0] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10046] +DisplayName=MastSlavNormMaxDiff[0] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[0] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10047] +DisplayName=ScalingFactor[0] +Descr=g_tAxesWatch.afScalingFactor[0] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10048] +DisplayName=AxisEncValue[1] +Descr=DC_nEncoder[1] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10049] +DisplayName=AxisEncMastSlaveOffset[1] +Descr=l_anMasterSlaveEncoderOffset[1] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10050] +DisplayName=MasterSlaveDiff[1] +Descr=l_afMasterSlaveDiff[1] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10051] +DisplayName=MasterSlaveDiffMax[1] +Descr=l_afMasterSlaveDiffMax[1] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10052] +DisplayName=MastSlavRefMaxDiff[1] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[1] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10053] +DisplayName=MastSlavNormMaxDiff[1] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[1] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10054] +DisplayName=ScalingFactor[1] +Descr=g_tAxesWatch.afScalingFactor[1] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10055] +DisplayName=AxisEncValue[2] +Descr=DC_nEncoder[2] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10056] +DisplayName=AxisEncMastSlaveOffset[2] +Descr=l_anMasterSlaveEncoderOffset[2] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10057] +DisplayName=MasterSlaveDiff[2] +Descr=l_afMasterSlaveDiff[2] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10058] +DisplayName=MasterSlaveDiffMax[2] +Descr=l_afMasterSlaveDiffMax[2] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10059] +DisplayName=MastSlavRefMaxDiff[2] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[2] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10060] +DisplayName=MastSlavNormMaxDiff[2] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[2] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10061] +DisplayName=ScalingFactor[2] +Descr=g_tAxesWatch.afScalingFactor[2] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10062] +DisplayName=AxisEncValue[3] +Descr=DC_nEncoder[3] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10063] +DisplayName=AxisEncMastSlaveOffset[3] +Descr=l_anMasterSlaveEncoderOffset[3] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10064] +DisplayName=MasterSlaveDiff[3] +Descr=l_afMasterSlaveDiff[3] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10065] +DisplayName=MasterSlaveDiffMax[3] +Descr=l_afMasterSlaveDiffMax[3] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10066] +DisplayName=MastSlavRefMaxDiff[3] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[3] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10067] +DisplayName=MastSlavNormMaxDiff[3] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[3] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10068] +DisplayName=ScalingFactor[3] +Descr=g_tAxesWatch.afScalingFactor[3] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10069] +DisplayName=AxisEncValue[4] +Descr=DC_nEncoder[4] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10070] +DisplayName=AxisEncMastSlaveOffset[4] +Descr=l_anMasterSlaveEncoderOffset[4] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10071] +DisplayName=MasterSlaveDiff[4] +Descr=l_afMasterSlaveDiff[4] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10072] +DisplayName=MasterSlaveDiffMax[4] +Descr=l_afMasterSlaveDiffMax[4] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10073] +DisplayName=MastSlavRefMaxDiff[4] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[4] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10074] +DisplayName=MastSlavNormMaxDiff[4] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[4] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10075] +DisplayName=ScalingFactor[4] +Descr=g_tAxesWatch.afScalingFactor[4] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10076] +DisplayName=AxisEncValue[5] +Descr=DC_nEncoder[5] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10077] +DisplayName=AxisEncMastSlaveOffset[5] +Descr=l_anMasterSlaveEncoderOffset[5] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10078] +DisplayName=MasterSlaveDiff[5] +Descr=l_afMasterSlaveDiff[5] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10079] +DisplayName=MasterSlaveDiffMax[5] +Descr=l_afMasterSlaveDiffMax[5] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10080] +DisplayName=MastSlavRefMaxDiff[5] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[5] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10081] +DisplayName=MastSlavNormMaxDiff[5] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[5] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10082] +DisplayName=ScalingFactor[5] +Descr=g_tAxesWatch.afScalingFactor[5] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10083] +DisplayName=AxisEncValue[6] +Descr=DC_nEncoder[6] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10084] +DisplayName=AxisEncMastSlaveOffset[6] +Descr=l_anMasterSlaveEncoderOffset[6] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10085] +DisplayName=MasterSlaveDiff[6] +Descr=l_afMasterSlaveDiff[6] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10086] +DisplayName=MasterSlaveDiffMax[6] +Descr=l_afMasterSlaveDiffMax[6] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10087] +DisplayName=MastSlavRefMaxDiff[6] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[6] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10088] +DisplayName=MastSlavNormMaxDiff[6] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[6] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10089] +DisplayName=ScalingFactor[6] +Descr=g_tAxesWatch.afScalingFactor[6] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10090] +DisplayName=AxisEncValue[7] +Descr=DC_nEncoder[7] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10091] +DisplayName=AxisEncMastSlaveOffset[7] +Descr=l_anMasterSlaveEncoderOffset[7] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10092] +DisplayName=MasterSlaveDiff[7] +Descr=l_afMasterSlaveDiff[7] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10093] +DisplayName=MasterSlaveDiffMax[7] +Descr=l_afMasterSlaveDiffMax[7] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10094] +DisplayName=MastSlavRefMaxDiff[7] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[7] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10095] +DisplayName=MastSlavNormMaxDiff[7] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[7] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10096] +DisplayName=ScalingFactor[7] +Descr=g_tAxesWatch.afScalingFactor[7] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10097] +DisplayName=AxisEncValue[8] +Descr=DC_nEncoder[8] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10098] +DisplayName=AxisEncMastSlaveOffset[8] +Descr=l_anMasterSlaveEncoderOffset[8] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10099] +DisplayName=MasterSlaveDiff[8] +Descr=l_afMasterSlaveDiff[8] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10100] +DisplayName=MasterSlaveDiffMax[8] +Descr=l_afMasterSlaveDiffMax[8] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10101] +DisplayName=MastSlavRefMaxDiff[8] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[8] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10102] +DisplayName=MastSlavNormMaxDiff[8] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[8] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10103] +DisplayName=ScalingFactor[8] +Descr=g_tAxesWatch.afScalingFactor[8] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10104] +DisplayName=AxisEncValue[9] +Descr=DC_nEncoder[9] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10105] +DisplayName=AxisEncMastSlaveOffset[9] +Descr=l_anMasterSlaveEncoderOffset[9] +SysID=4120 +DataType=10 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10106] +DisplayName=MasterSlaveDiff[9] +Descr=l_afMasterSlaveDiff[9] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10107] +DisplayName=MasterSlaveDiffMax[9] +Descr=l_afMasterSlaveDiffMax[9] +SysID=4120 +DataType=4 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +TaskName=axeswtch + +[CONTROLVALUE_10108] +DisplayName=MastSlavRefMaxDiff[9] +Descr=g_tAxesWatch.afMastSlavRefMaxDiff[9] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10109] +DisplayName=MastSlavNormMaxDiff[9] +Descr=g_tAxesWatch.afMastSlavNormMaxDiff[9] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +[CONTROLVALUE_10110] +DisplayName=ScalingFactor[9] +Descr=g_tAxesWatch.afScalingFactor[9] +SysID=4120 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=-1 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// Debug-Commands +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_10000] +Descr=del_Filament_Q +SysID=1 +DisplayName=DelFilamentQ + +[CONTROLCOMMAND_10001] +Descr=del_Target_Ws +SysID=1 +DisplayName=DelTargetJ + +[CONTROLCOMMAND_10002] +Descr=Sys_errorquit +SysID=1 +DisplayName=ResetSysErrArray + +[CONTROLCOMMAND_10003] +Descr=HSG_errorquit +SysID=1 +DisplayName=ResetHSGErrArray + +[CONTROLCOMMAND_10004] +Descr=Tube_errorquit +SysID=1 +DisplayName=ResetTubeErrArray + +[CONTROLCOMMAND_10005] +Descr=Vac_errorquit +SysID=1 +DisplayName=ResetVacErrArray + +;//////////////////////////////////////////////////////////////////////////////////////// +;// erweiterte Test-Variablen +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_15000] +DisplayName=TMTApertureCurrentArray +Descr=BlendeAbtast +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=1200 +DataLen=300 + +[CONTROLVALUE_15001] +DisplayName=TMTTargetCurrentArray +Descr=TargetAbtast +DataType=4 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=1200 +DataLen=300 + +[CONTROLVALUE_15002] +DisplayName=TMTIntegrationCount +Descr=burn_Anzahl +SysID=1 +DataType=10 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_15003] +DisplayName=TMTFocusVariation +Descr=burn_Ifocus +SysID=1 +DataType=4 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=250 + +[CONTROLVALUE_15004] +DisplayName=TMTFocusIntervall +Descr=burn_Ifocus_step +SysID=1 +DataType=4 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=250 + +[CONTROLVALUE_15005] +DisplayName=TMTUsedFocusPoints +Descr=abtast_ende +SysID=1 +DataType=10 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_15006] +DisplayName=TMTActFocusPoint +Descr=abtast_index +SysID=1 +DataType=10 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_15007] +DisplayName=TMTAccVoltage +Descr=burn_kV +SysID=1 +DataType=4 +ValueType=1 +Active=0 +Notify=0 +Hysterese=1.0 +RefreshTime=250 + +[CONTROLVALUE_15008] +DisplayName=TMTTubeCurrent +Descr=burn_mA +SysID=1 +DataType=4 +ValueType=1 +Active=0 +Notify=0 +Hysterese=1.0 +RefreshTime=250 + +[CONTROLVALUE_15009] +DisplayName=TMTResFocusOptMax +Descr=Focus_opt_max +SysID=1 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=250 + +[CONTROLVALUE_15010] +DisplayName=TMTResFocusOptMin +Descr=Focus_opt_min +SysID=1 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=250 + +[CONTROLVALUE_15011] +DisplayName=TMTResTargetAvgMax +Descr=TargetAverage_max +SysID=1 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=250 + +[CONTROLVALUE_15012] +DisplayName=TMTResTargetAvgMin +Descr=TargetAverage_min +SysID=1 +DataType=4 +ValueType=0 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=250 + +[CONTROLVALUE_15013] +DisplayName=TMTResult +Descr=TargetEinbrand +SysID=1 +DataType=6 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_15014] +DisplayName=BeamScanPointsPerLine +Descr=beamscan_anzahl +;//Variable wurde nach local verschoben +SysID=0 +DataType=11 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_15015] +DisplayName=BeamScanLineReady +Descr=beamscan_ready +;//Variable wurde nach local verschoben +SysID=0 +DataType=6 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 + +[CONTROLVALUE_15016] +DisplayName=BeamScanCurrentIntervall +Descr=beamscan_step +;//Variable wurde nach local verschoben +SysID=0 +DataType=11 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_15017] +DisplayName=BeamScanLineArray +Descr=beamscan_target +DataType=4 +ValueType=1 +;//Variable wurde nach local verschoben +SysID=0 +Active=0 +Notify=0 +Hysterese=0.1 +RefreshTime=1000 +DataLen=501 + +[CONTROLVALUE_15018] +DisplayName=BeamScanXIndex +Descr=beamscan_x +;//Variable wurde nach local verschoben +SysID=0 +DataType=11 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_15019] +DisplayName=BeamScanYIndex +Descr=beamscan_y +;//Variable wurde nach local verschoben +SysID=0 +DataType=11 +ValueType=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=250 + +[CONTROLVALUE_15020] +Descr=Tube.wobstep +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=WobbelStep + +[CONTROLVALUE_15021] +Descr=I_tube_korr +DataType=4 +ValueType=1 +SysID=0 +Active=0 +Notify=0 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=TubeCorrCurArray[A] +DataLen=11 + +[CONTROLVALUE_15022] +Descr=Tube.hub +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=WobbelAmplitude + +;//////////////////////////////////////////////////////////////////////////////////////// +;// Commandos fuer erweiterte Testfunktionen +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_15000] +Descr=PC_cmd.burn +DisplayName=StartTargetMaterialTest +SysID=1 + +[CONTROLCOMMAND_15001] +Descr=PC_cmd.beamscan +DisplayName=StartBeamScan +SysID=1 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// Stati fuer erweiterte Testfunktionen +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLSTATUS_15000] +DisplayName=TMTRunning +Descr=PLC_stat.bo_burn_is_running +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 + +[CONTROLSTATUS_15001] +DisplayName=BeamScanRunning +Descr=PLC_stat.bo_beamscan_is_running +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 + +[CPUTYPES] +I386="CP340 CP360 CP380 CP570 CP1483 CP1484 CP1583" +68000="IF260 CP260 CP430 CP476" + +;//////////////////////////////////////////////////////////////////////////////////////// +;// DATENMODULE +;//////////////////////////////////////////////////////////////////////////////////////// +; 26.06.2003: ModuleNameIdxMethod +; 0: alter Mechanismus (ModuleCount aus ini-Datei, 1-dim. Index) +; 1: [init-DM-Eintrag] (statisch, 1 Modul pro Init, z. B. hsg, tube) +; 2: [init-DM-Eintrag / Init-Anz.] (statisch, mehrere Module pro Init, z. B. amp, cent) +; 3: [Anz. init-DMs bzw. tubeheads (sollte gleich sein)] (statisch) +; 4: [Tubeheads] (1-dim., dyn.) +; 5: [Targets] (2-dim., dyn.) +; 6: [Modes] (3-dim., dyn.) +; Wenn ModuleNameIdxMethod=1 (z.B. cent, amp) dann wird der ModuleCount aus dem Eintrag im letzten init-dm ermittelt, +; es mssen dann diese Anz. Module angezeigt werden. +; Wenn ModuleNameIdxMethod=0 wird ModuleCount=0/1 gesetzt, es wird nur ein Modul angezeigt (und es gibt dann auch nur EINE +; Strukturvariable!) +; bei dyn. Modulen (mode, target) ergibt sich die anzuzeigende Anz. Module aus dem Wert der entspr. Variablen +; (z.B. cons_max, target_max) +;//////////////////////////////////////////////////////////////////////////////////////// +; INIT-Datenmodule: +; Diese liefern die Informationen darber, wieviele der anderen DMs insgesamt auf der RPS +; vorhanden und welche gerade aktiv sind. Momentan soll es fr jeden Rhrenkopf ein init-Datenmodul +; geben. ber einen dig. Eingang wird der jeweilige Rhrenkopf von der RPS erkannt --> Zu- +; weisung der Rhrenkopf-Nummer. Entspr. dieser Nummber wird ein init-DM angesprochen, in +; welchem hinterlegt ist, welche DMs aktiviert werden sollen. +; Definition/Konvention: IM LETZTEN init-DM steht die ANZAHL der fr jeden Typ auf der RPS +; vorhandenen DMs! +; init-DMs mssen nicht ber eine PC-Applikation angezeigt/konfiguriert werden! +;//////////////////////////////////////////////////////////////////////////////////////// +[INITDM] +DisplayName=InitDM +SysID=1 + +[TUBEHEADDM] +DisplayName=TubeheadDM +SysID=1 + +[TARGETDM] +DisplayName=TargetDM +SysID=1 + +[TargetDM_Names] +Descr=target.Name[%d] +DataType=9 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=2000 +DataLen=41 + +[MODEDM] +DisplayName=ModeDM +SysID=1 + +[ModeDM_Names] +Descr=Mode.Name[%d] +DataType=9 +ValueType=1 +SysID=1 +Active=0 +Notify=0 +Hysterese=0 +RefreshTime=2000 +DataLen=16 + +[FILDM] +DisplayName=FilDM +SysID=1 + +[TUBEDM] +DisplayName=TubeDM +SysID=513 + +[AMPDM] +DisplayName=AmpDM +SysID=1 + +[HSGDM] +DisplayName=HSGDM +SysID=513 + +[VACDM] +DisplayName=VacDM +SysID=1 + +[CONDDM] +DisplayName=CondDM +SysID=1 + +[SYSDM] +DisplayName=SysDM +SysID=513 + +[FOCUSDM] +DisplayName=FocusDM +SysID=1 + +[CONSDM] +DisplayName=ConsDM +SysID=2 + +[SHUTDM] +DisplayName=ShutDM +SysID=32 + +[CENTDM] +DisplayName=CentDM +SysID=1 + +[TREGDM] +DisplayName=TRegDM +SysID=64 + +[SYSMANIDM] +DisplayName=SysManiDM +SysID=4120 + +[PARA_DM] +DisplayName=ParaDM +SysID=4120 + +[GEODM] +DisplayName=GeoDM +SysID=4120 + +[REFDM] +DisplayName=RefDM +SysID=4120 + +[DOORDM] +DisplayName=DoorDM +SysID=4120 + +[MOTIRISDM] +DisplayName=MotIrisDM +SysID=1024 + +[JSPEEDDM] +DisplayName=JSpeedDM +SysID=4120 + +[AXESWATCHDM] +DisplayName=AxesWatchDM +SysID=4120 + +[LOADPOSDM] +DisplayName=LoadPosDM +SysID=4120 + +[MANIPARADM] +DisplayName=ManiParaDM +SysID=4120 + +[TURNTABLEDM] +DisplayName=TurntableDM +SysID=4120 + +[CAMAXISDM] +DisplayName=CamAxisDM +SysID=4120 + +[ACTAXISDM] +DisplayName=ACTAxisDM +SysID=4120 + +[AIMMASKDM] +DisplayName=AimMaskDM +SysID=4120 + +[RELJOYDM] +DisplayName=RelJoyDM +SysID=4120 diff --git a/XP.Hardware.RaySource/ReleaseFiles/fx_user.ini b/XP.Hardware.RaySource/ReleaseFiles/fx_user.ini new file mode 100644 index 0000000..7b8197f --- /dev/null +++ b/XP.Hardware.RaySource/ReleaseFiles/fx_user.ini @@ -0,0 +1,4359 @@ +[FOCUSTABLE0] +Description=FocusCharacteristic.i_t_table +SysID=1 + +[FOCUSTABLE1] +Description=CondensorCharacteristic.i_t_table +SysID=2 + +[FOCUSTABLE2] +Description=k_shut +SysID=32 + +[CENTERINGTABLE0] +Description=CenteringCharacteristic[0].x_y_t_table +SysID=1 + +[CENTERINGTABLE1] +Description=CenteringCharacteristic[1].x_y_t_table +SysID=128 + +[TUBECURRENTTABLE] +Description=TubecurrentCharacteristic.i_t_table +ElementCount=250 +SysID=512 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// VALUES +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_0] +Descr=PC_cmd.r32_TubeVoltage_kV +DataType=4 +ValueType=1 +SysID=769 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=AccVoltageNom[kV] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_1] +Descr=PC_cmd.r32_TubeCurrent_uA +DataType=4 +ValueType=1 +SysID=769 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1200 +DisplayName=TubeCurrentNom[A] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_2] +Descr=ISOwatt +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=500 +DisplayName=IsowattPower[W] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_3] +Descr=Sys.errornum +DataType=11 +ValueType=5 +SysID=513 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SystemErrorNumber +ReadSyncDef=0 + +[CONTROLVALUE_4] +Descr=Tube.kVmax +DataType=4 +ValueType=3 +SysID=769 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=AccVoltageMax[kV] +ReadSyncDef=0 + +[CONTROLVALUE_5] +Descr=PLC_stat.r32_TubeVoltage_kV_min +DataType=4 +;ConnectID for FFCom +ConID=2005 +ValueType=2 +SysID=769 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=AccVoltageMin[kV] +ReadSyncDef=0 + +[CONTROLVALUE_6] +Descr=Tube.mAmax +DataType=4 +ValueType=3 +SysID=769 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=TubeCurrentMax[A] +ReadSyncDef=0 + +[CONTROLVALUE_7] +Descr=HSG.FILmax +DataType=4 +ValueType=3 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=FilCurrentMax[A] +ReadSyncDef=0 + +[CONTROLVALUE_8] +Descr=HSG.errornum +DataType=11 +ValueType=5 +SysID=513 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=HSGErrorNumber +ReadSyncDef=0 + +[CONTROLVALUE_9] +Descr=TUBE_DM.kVmax +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=2000 +DisplayName=TubeDM_AccVoltMax[kV] +ReadSyncDef=0 + +[CONTROLVALUE_10] +Descr=TUBE_DM.mAmax +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=2000 +DisplayName=TubeDM_TubeCurMax[A] +ReadSyncDef=0 + +[CONTROLVALUE_11] +Descr=Mode.Target_Pmax +DataType=4 +ValueType=3 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=IsowattPowerMax[W] +ReadSyncDef=0 + +[CONTROLVALUE_12] +Descr=Tube.errornum +DataType=11 +ValueType=5 +SysID=513 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=TubeErrorNumber +ReadSyncDef=0 + +[CONTROLVALUE_13] +Descr=PLC_stat.r32_TubeVoltage_kV_max +DataType=4 +ValueType=3 +SysID=769 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1000 +DisplayName=Warmup_AccVoltMax[kV] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_14] +Descr=PLC_stat.r32_TubeVoltage_kV_ist +DataType=4 +ValueType=0 +SysID=769 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=AccVoltageAct[kV] +ReadSyncDef=0 + +[CONTROLVALUE_15] +Descr=PLC_stat.r32_TubeCurrent_uA_ist +DataType=4 +ValueType=0 +SysID=769 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=TubeCurrentAct[A] +ReadSyncDef=0 + +[CONTROLVALUE_16] +Descr=Targetleistung +DataType=4 +ValueType=0 +SysID=257 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=800 +DisplayName=TargetPowerAct[W] +ReadSyncDef=0 + +[CONTROLVALUE_17] +Descr=FILsoll +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=1200 +DisplayName=FilCurrentNom[A] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_18] +Descr=HSG.FIList +DataType=4 +ValueType=0 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.4 +RefreshTime=1000 +DisplayName=FilCurrentAct[V] +ReadSyncDef=0 + +[CONTROLVALUE_19] +Descr=PC_cmd.r32_focussoll +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1200 +DisplayName=FocusCurrentNom[mA] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_20] +Descr=Focus.fmax +DataType=4 +ValueType=3 +SysID=1 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=FocusCurrentMax[mA] +ReadSyncDef=0 + +[CONTROLVALUE_21] +Descr=Condensor.csoll +DataType=4 +ValueType=1 +SysID=2 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1200 +DisplayName=CondensCurrentNom[mA] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_22] +Descr=Condensor.cmax +DataType=4 +ValueType=3 +SysID=2 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=CondensCurrentMax[mA] +ReadSyncDef=0 + +[CONTROLVALUE_23] +Descr=Shutter.isoll +DataType=4 +ValueType=1 +SysID=32 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1200 +DisplayName=ShutterCurrentNom[mA] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_24] +Descr=Shutter.imax +DataType=4 +ValueType=3 +SysID=32 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=ShutterCurrentMax[mA] +ReadSyncDef=0 + +[CONTROLVALUE_25] +Descr=Shutter_on +DataType=6 +ValueType=1 +SysID=288 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ShutterOn[bool] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_26] +Descr=Cent[0].xsoll +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1200 +DisplayName=CentCurrentX1Nom[mA] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_27] +Descr=Cent[0].ysoll +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1200 +DisplayName=CentCurrentY1Nom[mA] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_28] +Descr=Cent[0].xmax +DataType=4 +ValueType=3 +SysID=1 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=CentCurrentX1Max[mA] +ReadSyncDef=0 + +[CONTROLVALUE_29] +Descr=Cent[0].ymax +DataType=4 +ValueType=3 +SysID=1 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=CentCurrentY1Max[mA] +ReadSyncDef=0 + +[CONTROLVALUE_30] +Descr=Cent[1].xsoll +DataType=4 +ValueType=1 +SysID=128 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1200 +DisplayName=CentCurrentX2Nom[mA] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_31] +Descr=Cent[1].ysoll +DataType=4 +ValueType=1 +SysID=128 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=1200 +DisplayName=CentCurrentY2Nom[mA] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_32] +Descr=Cent[1].xmax +DataType=4 +ValueType=3 +SysID=128 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=CentCurrentX2Max[mA] +ReadSyncDef=0 + +[CONTROLVALUE_33] +Descr=Cent[1].ymax +DataType=4 +ValueType=3 +SysID=128 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=CentCurrentY2Max[mA] +ReadSyncDef=0 + +[CONTROLVALUE_34] +Descr=Amp[1].ist +DataType=4 +ValueType=0 +SysID=257 +Active=1 +Notify=1 +Hysterese=0.3 +RefreshTime=500 +DisplayName=TargetCurrentAct[A] +ReadSyncDef=0 + +[CONTROLVALUE_35] +Descr=Amp[1].imax +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=TargetCurrentMax[A] +ReadSyncDef=0 + +[CONTROLVALUE_36] +Descr=Ptarget_max +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=700 +DisplayName=TargetPowerMax[W] +ReadSyncDef=0 + +[CONTROLVALUE_37] +Descr=Amp[2].ist +DataType=4 +ValueType=0 +SysID=34 +Active=1 +Notify=1 +Hysterese=0.3 +RefreshTime=500 +DisplayName=CondensApertureCurAct[A] +ReadSyncDef=0 + +[CONTROLVALUE_38] +Descr=Amp[2].imax +DataType=4 +ValueType=1 +SysID=34 +Active=0 +Notify=0 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=CondensApertureCurMax[A] +ReadSyncDef=0 + +[CONTROLVALUE_39] +Descr=Amp[3].ist +DataType=4 +ValueType=0 +;06.12.2002: Amp3-Variablen only for scanning! +SysID=34 +Active=1 +Notify=1 +Hysterese=0.3 +RefreshTime=500 +DisplayName=ObjApertureCurAct[A] +ReadSyncDef=0 + +[CONTROLVALUE_40] +Descr=Amp[3].imax +DataType=4 +ValueType=1 +;06.12.2002: Amp3-Variablen only for scanning! +SysID=34 +Active=0 +Notify=0 +Hysterese=1.0 +RefreshTime=1000 +DisplayName=ObjApertureCurMax[A] +ReadSyncDef=0 + +[CONTROLVALUE_41] +Descr=Ui_Vac +DataType=10 +ValueType=0 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.2 +RefreshTime=500 +DisplayName=VacuumAct[V] +ReadSyncDef=0 + +[CONTROLVALUE_42] +Descr=Vac.soll +DataType=4 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0.2 +RefreshTime=500 +DisplayName=VacuumNom[V] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_43] +Descr=Vac.errornum +DataType=11 +ValueType=5 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1000 +DisplayName=VacuumErrorNumber +ReadSyncDef=0 + +[CONTROLVALUE_44] +Descr=Ti_max +DataType=10 +ValueType=3 +SysID=64 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=TarCurMaxReg[A_as_short] +ReadSyncDef=0 + +[CONTROLVALUE_45] +Descr=Tireg.i_min +DataType=10 +ValueType=2 +SysID=64 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=TarCurMinReg[A_as_short] +ReadSyncDef=0 + +[CONTROLVALUE_46] +Descr=PLC_stat.bo_TXI +; Nano-Fox sometimes DataType = 6 or 10 +DataType=6 +ValueType=0 +SysID=320 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=TargetCurRegEnabled[int] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_47] +Descr=Mode.current_mode_number +DataType=11 +ValueType=1 +SysID=257 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=Mode +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_48] +Descr=Mode.last_mode_number +DataType=11 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=ModeCount +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_49] +Descr=Condensor.P_target_automatic +DataType=6 +ValueType=1 +SysID=258 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=SwitchAutoModeOn[int] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_50] +DisplayName=ActModeName +Descr=Mode.current_mode_name +SysID=1 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DataLen=16 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_51] +DisplayName=ActTargetName +Descr=target.current_target_name +SysID=1 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=-1 +DataLen=41 + +[CONTROLVALUE_52] +DisplayName=ActTubeheadName +Descr=Tubehead.current_tubehead_name +SysID=1 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=-1 +DataLen=16 + +[CONTROLVALUE_53] +Descr=PLC_cmd.reload_focusCharacteristic +DataType=6 +ValueType=1 +SysID=1 +; Do NOT set Active to 0 here ! +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=FocusTableChanged[bool] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_54] +Descr=PLC_cmd.reload_condensorCharacteristic +DataType=6 +ValueType=1 +SysID=2 +; Do NOT set Active to 0 here ! +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=CondensTableChanged[bool] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_55] +Descr=PLC_cmd.reload_centeringCharacteristic +DataType=6 +ValueType=1 +SysID=1 +; Do NOT set Active to 0 here ! +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=CentTableChanged[bool] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_56] +;wird ab FXEControl 3.0 nicht mehr verwendet +Descr=HSG.FIL_auto_adjust +DataType=6 +ValueType=1 +SysID=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=EnableAutomaticFilAdj[bool] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_57] +;wird ab FXEControl 3.0 nicht mehr verwendet +Descr=Tube.cent_auto_adjust +DataType=6 +ValueType=1 +SysID=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=EnableAutomaticACkV[bool] +WriteSyncDef=0 +ReadSyncDef=0 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSEN-VARIABLEN +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE1 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_58] +Descr=l_ptDpr.atAxisValues[0].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis1 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_59] +Descr=l_ptDpr.atAxisValues[0].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis1 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_60] +Descr=l_ptDpr.atAxisValues[0].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis1 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_61] +Descr=l_ptDpr.atAxisValues[0].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis1 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_62] +Descr=l_ptDpr.atAxisValues[0].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis1 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_63] +Descr=g_tManiCtrlStartOld.tAxis[0].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis1 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_64] +DisplayName=MinPositionAxis1 +Descr=l_ptDpr.atAxisValueLimits[0].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_65] +DisplayName=MaxPositionAxis1 +Descr=l_ptDpr.atAxisValueLimits[0].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_66] +Descr=g_tManiCtrlStartOld.tAxis[0].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis1 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_67] +DisplayName=MinSpeedAxis1 +Descr=l_ptDpr.atAxisValueLimits[0].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_68] +DisplayName=MaxSpeedAxis1 +Descr=l_ptDpr.atAxisValueLimits[0].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_69] +Descr=g_tManiCtrlStart.tAxis[0].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis1 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_70] +DisplayName=MaxAccelerationAxis1 +Descr=l_ptDpr.atAxisValueLimits[0].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_71] +Descr=g_tManiCtrlManuellOld.tAxis[0].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis1 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_72] +DisplayName=StepsPerTurnAxis1 +Descr=l_ptDpr.atAxisValues[0].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_73] +DisplayName=DistPerTurnAxis1 +Descr=l_ptDpr.atAxisValues[0].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_74] +Descr=l_ptDpr.atAxisValues[0].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis1 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_75] +Descr=g_tManiParameters.tAxisDescription[0].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis1 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_76] +Descr=l_ptDpr.atAxisValues[0].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis1 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE2 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_77] +Descr=l_ptDpr.atAxisValues[1].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis2 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_78] +Descr=l_ptDpr.atAxisValues[1].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis2 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_79] +Descr=l_ptDpr.atAxisValues[1].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis2 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_80] +Descr=l_ptDpr.atAxisValues[1].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis2 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_81] +Descr=l_ptDpr.atAxisValues[1].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis2 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_82] +Descr=g_tManiCtrlStartOld.tAxis[1].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis2 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_83] +DisplayName=MinPositionAxis2 +Descr=l_ptDpr.atAxisValueLimits[1].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_84] +DisplayName=MaxPositionAxis2 +Descr=l_ptDpr.atAxisValueLimits[1].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_85] +Descr=g_tManiCtrlStartOld.tAxis[1].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis2 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_86] +DisplayName=MinSpeedAxis2 +Descr=l_ptDpr.atAxisValueLimits[1].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_87] +DisplayName=MaxSpeedAxis2 +Descr=l_ptDpr.atAxisValueLimits[1].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_88] +Descr=g_tManiCtrlStart.tAxis[1].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis2 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_89] +DisplayName=MaxAccelerationAxis2 +Descr=l_ptDpr.atAxisValueLimits[1].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_90] +Descr=g_tManiCtrlManuellOld.tAxis[1].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis2 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_91] +DisplayName=StepsPerTurnAxis2 +Descr=l_ptDpr.atAxisValues[1].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_92] +DisplayName=DistPerTurnAxis2 +Descr=l_ptDpr.atAxisValues[1].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_93] +Descr=l_ptDpr.atAxisValues[1].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis2 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_94] +Descr=g_tManiParameters.tAxisDescription[1].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis2 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_95] +Descr=l_ptDpr.atAxisValues[1].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis2 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE3 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_96] +Descr=l_ptDpr.atAxisValues[2].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis3 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_97] +Descr=l_ptDpr.atAxisValues[2].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis3 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_98] +Descr=l_ptDpr.atAxisValues[2].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis3 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_99] +Descr=l_ptDpr.atAxisValues[2].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis3 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_100] +Descr=l_ptDpr.atAxisValues[2].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis3 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_101] +Descr=g_tManiCtrlStartOld.tAxis[2].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis3 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_102] +DisplayName=MinPositionAxis3 +Descr=l_ptDpr.atAxisValueLimits[2].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_103] +DisplayName=MaxPositionAxis3 +Descr=l_ptDpr.atAxisValueLimits[2].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_104] +Descr=g_tManiCtrlStartOld.tAxis[2].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis3 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_105] +DisplayName=MinSpeedAxis3 +Descr=l_ptDpr.atAxisValueLimits[2].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_106] +DisplayName=MaxSpeedAxis3 +Descr=l_ptDpr.atAxisValueLimits[2].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_107] +Descr=g_tManiCtrlStart.tAxis[2].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis3 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_108] +DisplayName=MaxAccelerationAxis3 +Descr=l_ptDpr.atAxisValueLimits[2].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_109] +Descr=g_tManiCtrlManuellOld.tAxis[2].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis3 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_110] +DisplayName=StepsPerTurnAxis3 +Descr=l_ptDpr.atAxisValues[2].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_111] +DisplayName=DistPerTurnAxis3 +Descr=l_ptDpr.atAxisValues[2].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_112] +Descr=l_ptDpr.atAxisValues[2].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis3 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_113] +Descr=g_tManiParameters.tAxisDescription[2].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis3 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_114] +Descr=l_ptDpr.atAxisValues[2].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis3 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE4 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_115] +Descr=l_ptDpr.atAxisValues[3].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis4 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_116] +Descr=l_ptDpr.atAxisValues[3].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis4 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_117] +Descr=l_ptDpr.atAxisValues[3].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis4 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_118] +Descr=l_ptDpr.atAxisValues[3].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis4 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_119] +Descr=l_ptDpr.atAxisValues[3].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis4 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_120] +Descr=g_tManiCtrlStartOld.tAxis[3].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis4 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_121] +DisplayName=MinPositionAxis4 +Descr=l_ptDpr.atAxisValueLimits[3].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_122] +DisplayName=MaxPositionAxis4 +Descr=l_ptDpr.atAxisValueLimits[3].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_123] +Descr=g_tManiCtrlStartOld.tAxis[3].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis4 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_124] +DisplayName=MinSpeedAxis4 +Descr=l_ptDpr.atAxisValueLimits[3].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_125] +DisplayName=MaxSpeedAxis4 +Descr=l_ptDpr.atAxisValueLimits[3].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_126] +Descr=g_tManiCtrlStart.tAxis[3].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis4 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_127] +DisplayName=MaxAccelerationAxis4 +Descr=l_ptDpr.atAxisValueLimits[3].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_128] +Descr=g_tManiCtrlManuellOld.tAxis[3].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis4 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_129] +DisplayName=StepsPerTurnAxis4 +Descr=l_ptDpr.atAxisValues[3].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_130] +DisplayName=DistPerTurnAxis4 +Descr=l_ptDpr.atAxisValues[3].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_131] +Descr=l_ptDpr.atAxisValues[3].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis4 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_132] +Descr=g_tManiParameters.tAxisDescription[3].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis4 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_133] +Descr=l_ptDpr.atAxisValues[3].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis4 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE5 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_134] +Descr=l_ptDpr.atAxisValues[4].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis5 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_135] +Descr=l_ptDpr.atAxisValues[4].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis5 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_136] +Descr=l_ptDpr.atAxisValues[4].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis5 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_137] +Descr=l_ptDpr.atAxisValues[4].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis5 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_138] +Descr=l_ptDpr.atAxisValues[4].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis5 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_139] +Descr=g_tManiCtrlStartOld.tAxis[4].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis5 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_140] +DisplayName=MinPositionAxis5 +Descr=l_ptDpr.atAxisValueLimits[4].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_141] +DisplayName=MaxPositionAxis5 +Descr=l_ptDpr.atAxisValueLimits[4].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_142] +Descr=g_tManiCtrlStartOld.tAxis[4].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis5 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_143] +DisplayName=MinSpeedAxis5 +Descr=l_ptDpr.atAxisValueLimits[4].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_144] +DisplayName=MaxSpeedAxis5 +Descr=l_ptDpr.atAxisValueLimits[4].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_145] +Descr=g_tManiCtrlStart.tAxis[4].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis5 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_146] +DisplayName=MaxAccelerationAxis5 +Descr=l_ptDpr.atAxisValueLimits[4].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_147] +Descr=g_tManiCtrlManuellOld.tAxis[4].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis5 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_148] +DisplayName=StepsPerTurnAxis5 +Descr=l_ptDpr.atAxisValues[4].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_149] +DisplayName=DistPerTurnAxis5 +Descr=l_ptDpr.atAxisValues[4].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_150] +Descr=l_ptDpr.atAxisValues[4].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis5 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_151] +Descr=g_tManiParameters.tAxisDescription[4].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis5 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_152] +Descr=l_ptDpr.atAxisValues[4].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis5 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE6 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_153] +Descr=l_ptDpr.atAxisValues[5].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis6 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_154] +Descr=l_ptDpr.atAxisValues[5].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis6 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_155] +Descr=l_ptDpr.atAxisValues[5].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis6 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_156] +Descr=l_ptDpr.atAxisValues[5].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis6 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_157] +Descr=l_ptDpr.atAxisValues[5].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis6 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_158] +Descr=g_tManiCtrlStartOld.tAxis[5].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis6 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_159] +DisplayName=MinPositionAxis6 +Descr=l_ptDpr.atAxisValueLimits[5].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_160] +DisplayName=MaxPositionAxis6 +Descr=l_ptDpr.atAxisValueLimits[5].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_161] +Descr=g_tManiCtrlStartOld.tAxis[5].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis6 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_162] +DisplayName=MinSpeedAxis6 +Descr=l_ptDpr.atAxisValueLimits[5].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_163] +DisplayName=MaxSpeedAxis6 +Descr=l_ptDpr.atAxisValueLimits[5].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_164] +Descr=g_tManiCtrlStart.tAxis[5].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis6 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_165] +DisplayName=MaxAccelerationAxis6 +Descr=l_ptDpr.atAxisValueLimits[5].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_166] +Descr=g_tManiCtrlManuellOld.tAxis[5].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis6 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_167] +DisplayName=StepsPerTurnAxis6 +Descr=l_ptDpr.atAxisValues[5].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_168] +DisplayName=DistPerTurnAxis6 +Descr=l_ptDpr.atAxisValues[5].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_169] +Descr=l_ptDpr.atAxisValues[5].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis6 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_170] +Descr=g_tManiParameters.tAxisDescription[5].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis6 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_171] +Descr=l_ptDpr.atAxisValues[5].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis6 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE7 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_172] +Descr=l_ptDpr.atAxisValues[6].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis7 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_173] +Descr=l_ptDpr.atAxisValues[6].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis7 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_174] +Descr=l_ptDpr.atAxisValues[6].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis7 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_175] +Descr=l_ptDpr.atAxisValues[6].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis7 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_176] +Descr=l_ptDpr.atAxisValues[6].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis7 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_177] +Descr=g_tManiCtrlStartOld.tAxis[6].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis7 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_178] +DisplayName=MinPositionAxis7 +Descr=l_ptDpr.atAxisValueLimits[6].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_179] +DisplayName=MaxPositionAxis7 +Descr=l_ptDpr.atAxisValueLimits[6].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_180] +Descr=g_tManiCtrlStartOld.tAxis[6].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis7 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_181] +DisplayName=MinSpeedAxis7 +Descr=l_ptDpr.atAxisValueLimits[6].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_182] +DisplayName=MaxSpeedAxis7 +Descr=l_ptDpr.atAxisValueLimits[6].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_183] +Descr=g_tManiCtrlStart.tAxis[6].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis7 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_184] +DisplayName=MaxAccelerationAxis7 +Descr=l_ptDpr.atAxisValueLimits[6].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_185] +Descr=g_tManiCtrlManuellOld.tAxis[6].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis7 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_186] +DisplayName=StepsPerTurnAxis7 +Descr=l_ptDpr.atAxisValues[6].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_187] +DisplayName=DistPerTurnAxis7 +Descr=l_ptDpr.atAxisValues[6].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_188] +Descr=l_ptDpr.atAxisValues[6].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis7 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_189] +Descr=g_tManiParameters.tAxisDescription[6].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis7 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_190] +Descr=l_ptDpr.atAxisValues[6].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis7 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE8 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_191] +Descr=l_ptDpr.atAxisValues[7].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis8 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_192] +Descr=l_ptDpr.atAxisValues[7].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis8 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_193] +Descr=l_ptDpr.atAxisValues[7].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis8 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_194] +Descr=l_ptDpr.atAxisValues[7].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis8 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_195] +Descr=l_ptDpr.atAxisValues[7].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis8 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_196] +Descr=g_tManiCtrlStartOld.tAxis[7].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis8 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_197] +DisplayName=MinPositionAxis8 +Descr=l_ptDpr.atAxisValueLimits[7].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_198] +DisplayName=MaxPositionAxis8 +Descr=l_ptDpr.atAxisValueLimits[7].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_199] +Descr=g_tManiCtrlStartOld.tAxis[7].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis8 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_200] +DisplayName=MinSpeedAxis8 +Descr=l_ptDpr.atAxisValueLimits[7].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_201] +DisplayName=MaxSpeedAxis8 +Descr=l_ptDpr.atAxisValueLimits[7].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_202] +Descr=g_tManiCtrlStart.tAxis[7].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis8 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_203] +DisplayName=MaxAccelerationAxis8 +Descr=l_ptDpr.atAxisValueLimits[7].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_204] +Descr=g_tManiCtrlManuellOld.tAxis[7].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis8 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_205] +DisplayName=StepsPerTurnAxis8 +Descr=l_ptDpr.atAxisValues[7].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_206] +DisplayName=DistPerTurnAxis8 +Descr=l_ptDpr.atAxisValues[7].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_207] +Descr=l_ptDpr.atAxisValues[7].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis8 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_208] +Descr=g_tManiParameters.tAxisDescription[7].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis8 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_209] +Descr=l_ptDpr.atAxisValues[7].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis8 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE9 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_210] +Descr=l_ptDpr.atAxisValues[8].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis9 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_211] +Descr=l_ptDpr.atAxisValues[8].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis9 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_212] +Descr=l_ptDpr.atAxisValues[8].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis9 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_213] +Descr=l_ptDpr.atAxisValues[8].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis9 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_214] +Descr=l_ptDpr.atAxisValues[8].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis9 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_215] +Descr=g_tManiCtrlStartOld.tAxis[8].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis9 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_216] +DisplayName=MinPositionAxis9 +Descr=l_ptDpr.atAxisValueLimits[8].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_217] +DisplayName=MaxPositionAxis9 +Descr=l_ptDpr.atAxisValueLimits[8].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_218] +Descr=g_tManiCtrlStartOld.tAxis[8].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis9 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_219] +DisplayName=MinSpeedAxis9 +Descr=l_ptDpr.atAxisValueLimits[8].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_220] +DisplayName=MaxSpeedAxis9 +Descr=l_ptDpr.atAxisValueLimits[8].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_221] +Descr=g_tManiCtrlStart.tAxis[8].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis9 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_222] +DisplayName=MaxAccelerationAxis9 +Descr=l_ptDpr.atAxisValueLimits[8].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_223] +Descr=g_tManiCtrlManuellOld.tAxis[8].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis9 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_224] +DisplayName=StepsPerTurnAxis9 +Descr=l_ptDpr.atAxisValues[8].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_225] +DisplayName=DistPerTurnAxis9 +Descr=l_ptDpr.atAxisValues[8].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_226] +Descr=l_ptDpr.atAxisValues[8].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis9 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_227] +Descr=g_tManiParameters.tAxisDescription[8].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis9 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_228] +Descr=l_ptDpr.atAxisValues[8].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis9 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE10 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLVALUE_229] +Descr=l_ptDpr.atAxisValues[9].dwAchsStatus +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=StatuswordAxis10 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_230] +Descr=l_ptDpr.atAxisValues[9].fIstPos +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=ActualPositionAxis10 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_231] +Descr=l_ptDpr.atAxisValues[9].fIstGeschw +DataType=4 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=250 +DisplayName=ActualSpeedAxis10 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_232] +Descr=l_ptDpr.atAxisValues[9].dwErrNummer +DataType=3 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorNumberAxis10 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_233] +Descr=l_ptDpr.atAxisValues[9].uErrAnzahl +DataType=11 +ValueType=0 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +DisplayName=ErrorCountAxis10 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_234] +Descr=g_tManiCtrlStartOld.tAxis[9].SollPos +DataType=1 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=DemandPositionAxis10 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_235] +DisplayName=MinPositionAxis10 +Descr=l_ptDpr.atAxisValueLimits[9].fNewNegSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_236] +DisplayName=MaxPositionAxis10 +Descr=l_ptDpr.atAxisValueLimits[9].fNewPosSW_End +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_237] +Descr=g_tManiCtrlStartOld.tAxis[9].SollGeschw +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandSpeedAxis10 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_238] +DisplayName=MinSpeedAxis10 +Descr=l_ptDpr.atAxisValueLimits[9].fMin_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_239] +DisplayName=MaxSpeedAxis10 +Descr=l_ptDpr.atAxisValueLimits[9].fMax_Geschw +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_240] +Descr=g_tManiCtrlStart.tAxis[9].fSollBeschl +DataType=4 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=1.0 +RefreshTime=500 +DisplayName=DemandAccelerationAxis10 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_241] +DisplayName=MaxAccelerationAxis10 +Descr=l_ptDpr.atAxisValueLimits[9].fMax_Beschl +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.5 +RefreshTime=2000 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_242] +Descr=g_tManiCtrlManuellOld.tAxis[9].Override +DataType=10 +ValueType=1 +;only TIGER (and Cougar15?) +SysID=4112 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=500 +DisplayName=SpeedFactorAxis10 +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_243] +DisplayName=StepsPerTurnAxis10 +Descr=l_ptDpr.atAxisValues[9].tAxisParameter.fMotSchritte +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_244] +DisplayName=DistPerTurnAxis10 +Descr=l_ptDpr.atAxisValues[9].tAxisParameter.fEinheiten +SysID=4120 +DataType=4 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0.1 +RefreshTime=2000 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_245] +Descr=l_ptDpr.atAxisValues[9].tAxisParameter.szAchsname +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=NameAxis10 +TaskName=pp_mast +ReadSyncDef=0 + +[CONTROLVALUE_246] +Descr=g_tManiParameters.tAxisDescription[9].szAxesScale +SysID=4120 +DataType=9 +ValueType=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=2000 +DataLen=16 +DisplayName=UnitAxis10 +;Nano-Fox: +TaskName= +ReadSyncDef=0 + +[CONTROLVALUE_247] +Descr=l_ptDpr.atAxisValues[9].bJoystickEnable +DataType=6 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=JoystickEnableAxis10 +WriteSyncDef=0 +ReadSyncDef=0 +TaskName=pp_mast + +[CONTROLVALUE_248] +DisplayName=AxisCountAll +Descr=g_tManiParameters.uMaxAxes +SysID=4120 +DataType=11 +ValueType=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=1250 +ReadSyncDef=0 + +[CONTROLVALUE_249] +Descr=PLC_stat.bo_flash_detected +DataType=6 +ValueType=1 +SysID=1 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=250 +DisplayName=Breakdown[bool] +ReadSyncDef=0 + +[CONTROLVALUE_250] +Descr=sys_status +DataType=3 +ValueType=1 +SysID=769 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=XRayStatus[BitArray] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_251] +Descr=g_dwManipulatorStatus +DataType=3 +ValueType=1 +SysID=4120 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=20 +DisplayName=ManipulatorStatus[BitArray] +WriteSyncDef=0 +ReadSyncDef=0 + +[CONTROLVALUE_252] +Descr=filter_nr +DataType=10 +ValueType=1 +;SysID=4376 +; currently not implemented on Mani-RPS (relevant for Aim und collision area) +SysID=0 +Active=1 +Notify=1 +Hysterese=0 +RefreshTime=100 +DisplayName=TubeFilterNumber +WriteSyncDef=0 +ReadSyncDef=0 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// STATI +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLSTATUS_0] +Descr=PLC_stat.bo_Xray_on +SysID=513 +Active=1 +Notify=1 +RefreshTime=150 +DisplayName=IsXRayOn + +[CONTROLSTATUS_1] +Descr=PLC_stat.bo_startup_is_running +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsStartingUp + +[CONTROLSTATUS_2] +Descr=PLC_stat.bo_warmup_is_running +SysID=513 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsWarmingUp + +[CONTROLSTATUS_3] +Descr=warmup +SysID=513 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsWarmupDone + +[CONTROLSTATUS_4] +Descr=PLC_stat.bo_filamentadjust_is_running +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsFilamentAdjusting + +[CONTROLSTATUS_5] +Descr=PLC_stat.bo_autocenter_kV_is_running +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsAutocenteringKV + +[CONTROLSTATUS_6] +Descr=PLC_stat.bo_autocenter_all_is_running +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsAutocenteringAll + +[CONTROLSTATUS_7] +Descr=PLC_stat.bo_conditioning_is_running +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsConditioning + +[CONTROLSTATUS_8] +Descr=PLC_stat.bo_wobbeln_is_active +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsSweepModeOn + +[CONTROLSTATUS_9] +Descr=PLC_stat.bo_interlock +SysID=769 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsInterlockOn + +[CONTROLSTATUS_10] +Descr=Tube.defoc +SysID=257 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsMicrofocusModeOff + +[CONTROLSTATUS_11] +Descr=PLC_stat.bo_Isowatt +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsIsowattOn + +[CONTROLSTATUS_12] +Descr=HSG.ok +SysID=513 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsHSGOk + +[CONTROLSTATUS_13] +Descr=kVok +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsAccVoltageOk + +[CONTROLSTATUS_14] +Descr=mAok +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsTubeCurrentOk + +[CONTROLSTATUS_15] +Descr=Vac.ok +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsVacuumOk + +[CONTROLSTATUS_16] +Descr=Target_reg +SysID=320 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsTargetRegulationOn + +[CONTROLSTATUS_17] +;wird ab FXEControl 3.0 nicht mehr verwendet +Descr=want_FIL_adjust +SysID=0 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=AutomaticFilAdj + +[CONTROLSTATUS_18] +;wird ab FXEControl 3.0 nicht mehr verwendet +Descr=want_cent_adjust +SysID=0 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=AutomaticACkV + +[CONTROLSTATUS_19] +Descr=PLC_stat.bo_offsetadjust_is_running +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=AmpOffsetAdjust + +[CONTROLSTATUS_20] +Descr=TP_HSGwarmup.Q +SysID=768 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=GeneratorWarmup +TaskName=system + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSEN-ZUSTNDE +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLSTATUS_21] +Descr=Door_open +SysID=4120 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsDoorOpen + +[CONTROLSTATUS_22] +Descr=Door_closed +SysID=4120 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=IsDoorClosed + +[CONTROLSTATUS_23] +; 09.08.05: ab RPS V. 2.6 gibt es keine Variable namens "Beladepos" mehr. Im Moment weiss keiner ob sie nur umbenannt wurde +; oder ob es sie gar nicht mehr gibt (auer vielleicht Armin, der ist im Urlaub) +; sie ist aber NOTWENDIG fr FNCBasic-Fahrbefehle, wenn eine Beladefahrt definiert ist, +; da sonst kein Acknowledge kommt wenn von FNC aus Fahrbefehl abgeschickt wird und Beladefahrt gerade +; ausgefhrt wird! +; Notlsung: Es wird die gleiche Variable wie fr den Befehl genommen, die soll laut Benjamin so lange auf true stehen +; wie die Beladefahrt luft. Das FNC sollte aber nochmal daraufhin getestet werden! +; Man knnte auch das Manipulator-Statuswort verwenden, dort muss diese Information auch hinterlegt werden; Problem ist +; nur, da unschne Abfragen notwendig sind, da die PC-Software abwrtskompatibel sein soll (if RPS-Version>=2.6) +; 13.09.05: Ab Version 2.7 soll wieder eine Zustandsvariable eingebaut sein! +Descr=Beladepos +SysID=0 +Active=1 +Notify=1 +RefreshTime=50 +DisplayName=DrivingToLoadPos +TaskName=pp_mast + +[CONTROLSTATUS_24] +Descr=PLC_stat.bo_xraytimer_on +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=cmd_Xraytimer_on + +[CONTROLSTATUS_25] +Descr=PLC_stat.bo_xraytimer_Reset +SysID=1 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=cmd_Xraytimer_reset + +[CONTROLSTATUS_26] +Descr=PLC_stat.bo_cond_Character_kV_is_running +SysID=257 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=AutoCondenserKv + +[CONTROLSTATUS_27] +Descr=PLC_stat.bo_cond_Character_SM_is_running +SysID=257 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=AutoCondenserMod + +[CONTROLSTATUS_28] +Descr=PLC_stat.bo_cond_Character_MM_is_running +SysID=257 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=AutoCondenserAll + +[CONTROLSTATUS_29] +Descr=PLC_stat.bo_filamentcorradjust_is_running +SysID=257 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=FilamentCorrectionTest + +[CONTROLSTATUS_30] +Descr=PLC_stat.bo_leckstrom_is_running +SysID=257 +Active=1 +Notify=1 +RefreshTime=250 +DisplayName=LeakageCurrentTest + +;//////////////////////////////////////////////////////////////////////////////////////// +;// COMMANDS +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_0] +Descr=PC_cmd.xrayON +SysID=769 +DisplayName=SwitchXRayOn +WriteSyncDef=0 + +[CONTROLCOMMAND_1] +Descr=PC_cmd.xrayOFF +SysID=769 +DisplayName=SwitchXRayOff +WriteSyncDef=0 + +[CONTROLCOMMAND_2] +Descr=PC_cmd.startUP +SysID=257 +DisplayName=StartUp +WriteSyncDef=0 + +[CONTROLCOMMAND_3] +Descr=PC_cmd.warmUP +SysID=769 +DisplayName=WarmUp +WriteSyncDef=0 + +[CONTROLCOMMAND_4] +Descr=PC_cmd.isoON +SysID=1 +DisplayName=SwitchIsowattOn +WriteSyncDef=0 + +[CONTROLCOMMAND_5] +Descr=PC_cmd.isoOFF +SysID=1 +DisplayName=SwitchIsowattOff +WriteSyncDef=0 + +[CONTROLCOMMAND_6] +Descr=PC_cmd.filamentadjust +SysID=257 +DisplayName=DoFilamentAdj +WriteSyncDef=0 + +[CONTROLCOMMAND_7] +Descr=PC_cmd.autocentkV +SysID=257 +DisplayName=DoAutocenterKV +WriteSyncDef=0 + +[CONTROLCOMMAND_8] +Descr=PC_cmd.autocentALL +SysID=257 +DisplayName=DoAutocenterAll +WriteSyncDef=0 + +[CONTROLCOMMAND_9] +Descr=PC_cmd.conditioning +SysID=1 +DisplayName=DoConditioning +WriteSyncDef=0 + +[CONTROLCOMMAND_10] +Descr=PC_cmd.wobbelON +SysID=1 +DisplayName=SwitchSweepModeOn +WriteSyncDef=0 + +[CONTROLCOMMAND_11] +Descr=PC_cmd.wobbelOFF +SysID=1 +DisplayName=SwitchSweepModeOff +WriteSyncDef=0 + +[CONTROLCOMMAND_12] +Descr=PC_cmd.focusCharacteristic.read +SysID=1 +DisplayName=ReadFocusTable +WriteSyncDef=0 + +[CONTROLCOMMAND_13] +Descr=PC_cmd.focusCharacteristic.write +SysID=1 +DisplayName=WriteFocusTable +WriteSyncDef=0 + +[CONTROLCOMMAND_14] +Descr=PC_cmd.focusCharacteristic.store_point +SysID=1 +DisplayName=StoreFocusTablePoint +WriteSyncDef=0 + +[CONTROLCOMMAND_15] +Descr=PC_cmd.focusCharacteristic.delete_point +SysID=1 +DisplayName=DelFocusTablePoint +WriteSyncDef=0 + +[CONTROLCOMMAND_16] +Descr=PC_cmd.focusCharacteristic.delete_all_points +SysID=1 +DisplayName=DelAllFocusTablePoints +WriteSyncDef=0 + +[CONTROLCOMMAND_17] +Descr=PC_cmd.condensorCharacteristic.read +SysID=2 +DisplayName=ReadCondensorTable +WriteSyncDef=0 + +[CONTROLCOMMAND_18] +Descr=PC_cmd.condensorCharacteristic.write +SysID=2 +DisplayName=WriteCondensorTable +WriteSyncDef=0 + +[CONTROLCOMMAND_19] +Descr=PC_cmd.condensorCharacteristic.store_point +SysID=2 +DisplayName=StoreCondensorTablePoint +WriteSyncDef=0 + +[CONTROLCOMMAND_20] +Descr=PC_cmd.condensorCharacteristic.delete_point +SysID=2 +DisplayName=DeleteCondensTablePoint +WriteSyncDef=0 + +[CONTROLCOMMAND_21] +Descr=PC_cmd.condensorCharacteristic.delete_all_points +SysID=2 +DisplayName=DelAllCondensTablePoints +WriteSyncDef=0 + +[CONTROLCOMMAND_22] +Descr=readshut +SysID=32 +DisplayName=ReadShutterTable +WriteSyncDef=0 + +[CONTROLCOMMAND_23] +Descr=writeshut +SysID=32 +DisplayName=WriteShutterTable +WriteSyncDef=0 + +[CONTROLCOMMAND_24] +Descr=storeshut +SysID=32 +DisplayName=StoreShutterTablePoint +WriteSyncDef=0 + +[CONTROLCOMMAND_25] +Descr=delshut_kV +SysID=32 +DisplayName=DelShutterTablePoint +WriteSyncDef=0 + +[CONTROLCOMMAND_26] +Descr=delshut_all +SysID=32 +DisplayName=DelAllShutterTablePoints +WriteSyncDef=0 + +[CONTROLCOMMAND_27] +Descr=PC_cmd.centeringCharacteristic[0].write +SysID=1 +DisplayName=WriteCenteringTable1 +WriteSyncDef=0 + +[CONTROLCOMMAND_28] +Descr=PC_cmd.centeringCharacteristic[0].read +SysID=1 +DisplayName=ReadCenteringTable1 +WriteSyncDef=0 + +[CONTROLCOMMAND_29] +Descr=PC_cmd.centeringCharacteristic[0].store_point +SysID=1 +DisplayName=StoreCenteringTable1Point +WriteSyncDef=0 + +[CONTROLCOMMAND_30] +Descr=PC_cmd.centeringCharacteristic[0].delete_point +SysID=1 +DisplayName=DelCenteringTable1Point +WriteSyncDef=0 + +[CONTROLCOMMAND_31] +Descr=PC_cmd.centeringCharacteristic[0].delete_all_points +SysID=1 +DisplayName=DelAllCentTable1Points +WriteSyncDef=0 + +[CONTROLCOMMAND_32] +Descr=PC_cmd.centeringCharacteristic[1].write +SysID=128 +DisplayName=WriteCenteringTable2 +WriteSyncDef=0 + +[CONTROLCOMMAND_33] +Descr=PC_cmd.centeringCharacteristic[1].read +SysID=128 +DisplayName=ReadCenteringTable2 +WriteSyncDef=0 + +[CONTROLCOMMAND_34] +Descr=PC_cmd.centeringCharacteristic[1].store_point +SysID=128 +DisplayName=StoreCentTable2Point +WriteSyncDef=0 + +[CONTROLCOMMAND_35] +Descr=PC_cmd.centeringCharacteristic[1].delete_point +SysID=128 +DisplayName=DelCentTable2Point +WriteSyncDef=0 + +[CONTROLCOMMAND_36] +Descr=PC_cmd.centeringCharacteristic[1].delete_all_points +SysID=128 +DisplayName=DelAllCentTable2Points +WriteSyncDef=0 + +[CONTROLCOMMAND_37] +Descr=PC_cmd.Ti_reg_on +SysID=320 +DisplayName=SwitchTargetCurRegOn +WriteSyncDef=0 + +[CONTROLCOMMAND_38] +Descr=PC_cmd.Ti_reg_off +SysID=320 +DisplayName=SwitchTargetCurRegOff +WriteSyncDef=0 + +[CONTROLCOMMAND_39] +Descr=PC_cmd.offsetadjust +SysID=64 +DisplayName=AdjustAmpOffset +WriteSyncDef=0 + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSEN-,MANIPULATOR-COMMANDS +;//////////////////////////////////////////////////////////////////////////////////////// +;// ALLGEMEIN +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_40] +Descr=PC_doortast +SysID=4120 +DisplayName=ExecuteDoorSwitch +WriteSyncDef=0 + +[CONTROLCOMMAND_41] +Descr=l_ptDpr.tManiCommands.bInitAxisAll +SysID=4120 +DisplayName=InitAllAxis +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_42] +Descr=l_ptDpr.tManiCommands.bDeInitAxisAll +SysID=4120 +DisplayName=ExitAllAxis +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_43] +Descr=l_ptDpr.tManiCommands.bStartReferenceAll +SysID=4120 +DisplayName=ReferenceAllAxis +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_44] +Descr=l_ptDpr.tManiCommands.bStopPositionAll +SysID=4120 +DisplayName=StopAllAxis +WriteSyncDef=1 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE1 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_46] +Descr=l_ptDpr.atAxisCommands[0].bInitAxis +SysID=4120 +DisplayName=InitAxis1 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_47] +Descr=l_ptDpr.atAxisCommands[0].bDeInitAxis +SysID=4120 +DisplayName=ExitAxis1 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_48] +Descr=l_ptDpr.atAxisCommands[0].bStartReference +SysID=4120 +DisplayName=ReferenceAxis1 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_49] +Descr=l_ptDpr.atAxisCommands[0].bStopPosition +SysID=4120 +DisplayName=StopPositioningAxis1 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_50] +Descr=l_ptDpr.atAxisCommands[0].bClearErrors +SysID=4120 +DisplayName=ErrorQuitAxis1 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE2 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_51] +Descr=l_ptDpr.atAxisCommands[1].bInitAxis +SysID=4120 +DisplayName=InitAxis2 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_52] +Descr=l_ptDpr.atAxisCommands[1].bDeInitAxis +SysID=4120 +DisplayName=ExitAxis2 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_53] +Descr=l_ptDpr.atAxisCommands[1].bStartReference +SysID=4120 +DisplayName=ReferenceAxis2 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_54] +Descr=l_ptDpr.atAxisCommands[1].bStopPosition +SysID=4120 +DisplayName=StopPositioningAxis2 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_55] +Descr=l_ptDpr.atAxisCommands[1].bClearErrors +SysID=4120 +DisplayName=ErrorQuitAxis2 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE3 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_56] +Descr=l_ptDpr.atAxisCommands[2].bInitAxis +SysID=4120 +DisplayName=InitAxis3 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_57] +Descr=l_ptDpr.atAxisCommands[2].bDeInitAxis +SysID=4120 +DisplayName=ExitAxis3 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_58] +Descr=l_ptDpr.atAxisCommands[2].bStartReference +SysID=4120 +DisplayName=ReferenceAxis3 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_59] +Descr=l_ptDpr.atAxisCommands[2].bStopPosition +SysID=4120 +DisplayName=StopPositioningAxis3 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_60] +Descr=l_ptDpr.atAxisCommands[2].bClearErrors +SysID=4120 +DisplayName=ErrorQuitAxis3 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE4 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_61] +Descr=l_ptDpr.atAxisCommands[3].bInitAxis +SysID=4120 +DisplayName=InitAxis4 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_62] +Descr=l_ptDpr.atAxisCommands[3].bDeInitAxis +SysID=4120 +DisplayName=ExitAxis4 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_63] +Descr=l_ptDpr.atAxisCommands[3].bStartReference +SysID=4120 +DisplayName=ReferenceAxis4 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_64] +Descr=l_ptDpr.atAxisCommands[3].bStopPosition +SysID=4120 +DisplayName=StopPositioningAxis4 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_65] +Descr=l_ptDpr.atAxisCommands[3].bClearErrors +SysID=4120 +DisplayName=ErrorQuitAxis4 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE5 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_66] +Descr=l_ptDpr.atAxisCommands[4].bInitAxis +SysID=4120 +DisplayName=InitAxis5 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_67] +Descr=l_ptDpr.atAxisCommands[4].bDeInitAxis +SysID=4120 +DisplayName=ExitAxis5 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_68] +Descr=l_ptDpr.atAxisCommands[4].bStartReference +SysID=4120 +DisplayName=ReferenceAxis5 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_69] +Descr=l_ptDpr.atAxisCommands[4].bStopPosition +SysID=4120 +DisplayName=StopPositioningAxis5 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_70] +Descr=l_ptDpr.atAxisCommands[4].bClearErrors +SysID=4120 +DisplayName=ErrorQuitAxis5 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE6 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_71] +Descr=l_ptDpr.atAxisCommands[5].bInitAxis +SysID=4120 +DisplayName=InitAxis6 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_72] +Descr=l_ptDpr.atAxisCommands[5].bDeInitAxis +SysID=4120 +DisplayName=ExitAxis6 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_73] +Descr=l_ptDpr.atAxisCommands[5].bStartReference +SysID=4120 +DisplayName=ReferenceAxis6 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_74] +Descr=l_ptDpr.atAxisCommands[5].bStopPosition +SysID=4120 +DisplayName=StopPositioningAxis6 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_75] +Descr=l_ptDpr.atAxisCommands[5].bClearErrors +SysID=4120 +DisplayName=ErrorQuitAxis6 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE7 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_76] +Descr=l_ptDpr.atAxisCommands[6].bInitAxis +SysID=4096 +DisplayName=InitAxis7 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_77] +Descr=l_ptDpr.atAxisCommands[6].bDeInitAxis +SysID=4096 +DisplayName=ExitAxis7 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_78] +Descr=l_ptDpr.atAxisCommands[6].bStartReference +SysID=4096 +DisplayName=ReferenceAxis7 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_79] +Descr=l_ptDpr.atAxisCommands[6].bStopPosition +SysID=4096 +DisplayName=StopPositioningAxis7 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_80] +Descr=l_ptDpr.atAxisCommands[6].bClearErrors +SysID=4096 +DisplayName=ErrorQuitAxis7 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE8 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_81] +Descr=l_ptDpr.atAxisCommands[7].bInitAxis +SysID=4096 +DisplayName=InitAxis8 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_82] +Descr=l_ptDpr.atAxisCommands[7].bDeInitAxis +SysID=4096 +DisplayName=ExitAxis8 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_83] +Descr=l_ptDpr.atAxisCommands[7].bStartReference +SysID=4096 +DisplayName=ReferenceAxis8 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_84] +Descr=l_ptDpr.atAxisCommands[7].bStopPosition +SysID=4096 +DisplayName=StopPositioningAxis8 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_85] +Descr=l_ptDpr.atAxisCommands[7].bClearErrors +SysID=4096 +DisplayName=ErrorQuitAxis8 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE9 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_86] +Descr=l_ptDpr.atAxisCommands[8].bInitAxis +SysID=4096 +DisplayName=InitAxis9 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_87] +Descr=l_ptDpr.atAxisCommands[8].bDeInitAxis +SysID=4096 +DisplayName=ExitAxis9 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_88] +Descr=l_ptDpr.atAxisCommands[8].bStartReference +SysID=4096 +DisplayName=ReferenceAxis9 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_89] +Descr=l_ptDpr.atAxisCommands[8].bStopPosition +SysID=4096 +DisplayName=StopPositioningAxis9 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_90] +Descr=l_ptDpr.atAxisCommands[8].bClearErrors +SysID=4096 +DisplayName=ErrorQuitAxis9 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +;//////////////////////////////////////////////////////////////////////////////////////// +;// ACHSE10 +;//////////////////////////////////////////////////////////////////////////////////////// +[CONTROLCOMMAND_91] +Descr=l_ptDpr.atAxisCommands[9].bInitAxis +SysID=4096 +DisplayName=InitAxis10 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_92] +Descr=l_ptDpr.atAxisCommands[9].bDeInitAxis +SysID=4096 +DisplayName=ExitAxis10 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_93] +Descr=l_ptDpr.atAxisCommands[9].bStartReference +SysID=4096 +DisplayName=ReferenceAxis10 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_94] +Descr=l_ptDpr.atAxisCommands[9].bStopPosition +SysID=4096 +DisplayName=StopPositioningAxis10 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast + +[CONTROLCOMMAND_95] +Descr=l_ptDpr.atAxisCommands[9].bClearErrors +SysID=4096 +DisplayName=ErrorQuitAxis10 +WriteSyncDef=0 +DataType=6 +TaskName=pp_mast diff --git a/XP.Hardware.RaySource/ReleaseFiles/fxerr.ini b/XP.Hardware.RaySource/ReleaseFiles/fxerr.ini new file mode 100644 index 0000000..ca10601 --- /dev/null +++ b/XP.Hardware.RaySource/ReleaseFiles/fxerr.ini @@ -0,0 +1,294 @@ +[XRaySystemErrors] +ErrorNumber0=101 +ErrorString0="Data module init error" +ErrorNumber1=102 +ErrorString1="Data module sys error" +ErrorNumber2=103 +ErrorString2="Data module amp error" +ErrorNumber3=301 +ErrorString3="Timeout during filament adjusting" +ErrorNumber4=302 +ErrorString4="Timeout during warmup" +ErrorNumber5=303 +ErrorString5="Error door control" +ErrorNumber6=401 +ErrorString6="Defective warn lamp 1" +ErrorNumber7=402 +ErrorString7="Defective warn lamp 2" +ErrorNumber8=403 +ErrorString8="Defective warn lamp 3" +ErrorNumber9=404 +ErrorString9="Cooling defect" +ErrorNumber10=405 +ErrorString10="Error COM2" +ErrorNumber11=406 +ErrorString12="Error COM2" +ErrorNumber13=407 +ErrorString13="Error COM2" +ErrorNumber14=408 +ErrorString14="Error COM2" +ErrorNumber15=601 +ErrorString15="Defective warn lamp 1" +ErrorNumber16=602 +ErrorString16="Defective warn lamp 2" +ErrorNumber17=603 +ErrorString17="Defective warn lamp 3" +ErrorNumber18=604 +ErrorString18="Cooling defect" +ErrorNumber19=605 +ErrorString19="Error COM2" + +[HSGErrors] +ErrorNumber0=101 +ErrorString0="Data module error" +ErrorNumber1=201 +ErrorString1="Underflow of actual accelerating voltage" +ErrorNumber2=202 +ErrorString2="Overflow of actual accelerating voltage" +ErrorNumber3=203 +ErrorString3="Underflow of actual tube current" +ErrorNumber4=204 +ErrorString4="Overflow of actual tube current" +ErrorNumber5=205 +ErrorString5="Underflow of actual filament current" +ErrorNumber6=206 +ErrorString6="Overflow of actual filament current" +ErrorNumber7=301 +ErrorString7="Timeout acceleration voltage" +ErrorNumber8=302 +ErrorString8="Timeout tube current" +ErrorNumber9=303 +ErrorString9="Timeout filament adjust" +ErrorNumber10=402 +ErrorString10="High voltage generator overload" +ErrorNumber11=403 +ErrorString11="No filament current" +ErrorNumber12=501 +ErrorString12="Overvlow of nominal filament current" +ErrorNumber13=502 +ErrorString13="Overflow or underflow of nominal accelerating voltage" +ErrorNumber14=503 +ErrorString14="Overflow of nominal tube current" +ErrorNumber15=510 +ErrorString15="Error during filament adjust step 30" +ErrorNumber16=520 +ErrorString16="Nominal filament current smaller than filament offset" +ErrorNumber17=524 +ErrorString17="Filament working current exceeds limit during filament adjust" +ErrorNumber18=525 +ErrorString18="Filament working current exceeds limit during filament adjust" +ErrorNumber19=526 +ErrorString19="Nominal filament current smaller than filament offset during filament adjust" +ErrorNumber19=527 +ErrorString19="Nominal filament current smaller than filament offset during filament adjust" + +[TubeErrors] +ErrorNumber0=101 +ErrorString0="Data module error" +ErrorNumber1=102 +ErrorString1="Data module focus table created" +ErrorNumber2=103 +ErrorString2="Focus data module write error" +ErrorNumber3=104 +ErrorString3="Focus data module error" +ErrorNumber4=105 +ErrorString4="Focus table data module info error" +ErrorNumber5=106 +ErrorString5="Focus table data module read error" +ErrorNumber6=107 +ErrorString6="Condensor data module error" +ErrorNumber7=108 +ErrorString7="Data module condensor table created" +ErrorNumber8=109 +ErrorString8="Condensor table data module info error" +ErrorNumber9=110 +ErrorString9="Condensor table data module read error" +ErrorNumber10=111 +ErrorString10="Centering 1 / Centering 2 / Centering 3 data module error" +ErrorNumber11=114 +ErrorString11="Centering table 1 data module error" +ErrorNumber12=115 +ErrorString12="Centering table 2 data module error" +ErrorNumber13=116 +ErrorString13="Centering table 3 data module error" +ErrorNumber14=117 +ErrorString14="Conditioning data module error" +ErrorNumber15=118 +ErrorString15="Read focus data module error" +ErrorNumber16=119 +ErrorString16="Write focus data module error" +ErrorNumber17=120 +ErrorString17="Read default focus data module error" +ErrorNumber18=121 +ErrorString18="Write default focus data module error" +ErrorNumber19=122 +ErrorString19="Read condensor data module error" +ErrorNumber20=123 +ErrorString20="Write condensor data module error" +ErrorNumber21=124 +ErrorString21="Read default condensor data module error" +ErrorNumber22=125 +ErrorString22="Write default condensor data module error" +ErrorNumber23=126 +ErrorString23="Read centering 1 data module error" +ErrorNumber24=127 +ErrorString24="Read centering 2 data module error" +ErrorNumber25=128 +ErrorString25="Read centering 3 data module error" +ErrorNumber26=129 +ErrorString26="Write centering 1 data module error" +ErrorNumber27=130 +ErrorString27="Write centering 2 data module error" +ErrorNumber28=131 +ErrorString28="Write centering 3 data module error" +ErrorNumber29=132 +ErrorString29="Read default centering 1 data module error" +ErrorNumber30=133 +ErrorString30="Read default centering 2 data module error" +ErrorNumber31=134 +ErrorString31="Read default centering 3 data module error" +ErrorNumber32=135 +ErrorString32="Write default centering 1 data module error" +ErrorNumber33=136 +ErrorString33="Write default centering 2 data module error" +ErrorNumber34=137 +ErrorString34="Write default centering 3 data module error" +ErrorNumber35=140 +ErrorString35="Shutter data module error" +ErrorNumber36=141 +ErrorString36="Data module shutter created" +ErrorNumber37=142 +ErrorString37="Shutter table data module info error" +ErrorNumber38=143 +ErrorString38="Shutter table data module read error" +ErrorNumber39=144 +ErrorString39="Scan data module error" +ErrorNumber40=145 +ErrorString40="Scan table data module error" +ErrorNumber41=146 +ErrorString41="Ti_Reg data module error" +ErrorNumber42=147 +ErrorString42="dm_ken (focus) data module error" +ErrorNumber43=148 +ErrorString43="dm_ken (condensor) data module error" +ErrorNumber44=149 +ErrorString44="Mode_x data module error" +ErrorNumber45=150 +ErrorString45="burn data module error" +ErrorNumber46=151 +ErrorString46="tube_cur data module error" +ErrorNumber47=152 +ErrorString47="Tubehead data module error" +ErrorNumber48=153 +ErrorString48="Target data module error" +ErrorNumber49=154 +ErrorString49="read_def_tube_cur data module error" +ErrorNumber50=155 +ErrorString50="write_def_tube_cur data module error" +ErrorNumber51=156 +ErrorString51="Filament data module error" +ErrorNumber52=201 +ErrorString52="Underflow of actual target (amp1) current" +ErrorNumber53=202 +ErrorString53="Overflow of actual target (amp1) current" +ErrorNumber54=203 +ErrorString54="Underflow of actual target (amp2) current" +ErrorNumber55=204 +ErrorString55="Overflow of actual target (amp2) current" +ErrorNumber56=205 +ErrorString56="Underflow of actual amp3 current" +ErrorNumber57=206 +ErrorString57="Overflow of actual amp3 current" +ErrorNumber58=301 +ErrorString58="Time limit for centering current overflow exeeded, x-ray switched off" +ErrorNumber59=302 +ErrorString59="Time limit for shutter exceeded, xray switched off" +ErrorNumber60=401 +ErrorString60="Overflow of target power" +ErrorNumber61=402 +ErrorString61="Missing amplifier" +ErrorNumber62=403 +ErrorString62="Scanning coil temperature overflow" +ErrorNumber63=501 +ErrorString63="Overflow of nominal focus current" +ErrorNumber64=502 +ErrorString64="Overflow of nominal centering current x" +ErrorNumber65=503 +ErrorString65="Overflow of nominal centering current y" +ErrorNumber66=504 +ErrorString66="Overflow of nominal centering current" +ErrorNumber67=505 +ErrorString67="Overflow of nominal shutter current" +ErrorNumber68=506 +ErrorString68="Overflow of actual focus current" +ErrorNumber69=507 +ErrorString69="Negative focus current" +ErrorNumber70=611 +ErrorString70="Error during autocentering (plane 1)" +ErrorNumber71=612 +ErrorString71="Error during autocentering (plane 1)" +ErrorNumber72=613 +ErrorString72="Error during autocentering (plane 1)" +ErrorNumber73=614 +ErrorString73="Error during autocentering (plane 1)" +ErrorNumber74=615 +ErrorString74="Error during autocentering (plane 1)" +ErrorNumber75=616 +ErrorString75="Error during autocentering (plane 1)" +ErrorNumber76=617 +ErrorString76="Max. number of runs for autocentering exceeded (plane 1)" +ErrorNumber77=618 +ErrorString77="Centering current exceeded (plane 1)" +ErrorNumber78=621 +ErrorString78="Error during autocentering (plane 2)" +ErrorNumber79=622 +ErrorString79="Error during autocentering (plane 2)" +ErrorNumber80=623 +ErrorString80="Error during autocentering (plane 2)" +ErrorNumber81=624 +ErrorString81="Error during autocentering (plane 2)" +ErrorNumber82=625 +ErrorString82="Error during autocentering (plane 2)" +ErrorNumber83=626 +ErrorString83="Error during autocentering (plane 2)" +ErrorNumber84=627 +ErrorString84="Max. number of runs for autocentering exceeded (plane 2)" +ErrorNumber85=628 +ErrorString85="Centering current exceeded (plane 2)" +ErrorNumber86=631 +ErrorString86="Error during autocentering (plane 3)" +ErrorNumber87=632 +ErrorString87="Error during autocentering (plane 3)" +ErrorNumber88=633 +ErrorString88="Error during autocentering (plane 3)" +ErrorNumber89=634 +ErrorString89="Error during autocentering (plane 3)" +ErrorNumber90=635 +ErrorString90="Error during autocentering (plane 3)" +ErrorNumber91=636 +ErrorString91="Error during autocentering (plane 3)" +ErrorNumber92=637 +ErrorString92="Max. number of runs for autocentering exceeded (plane 3)" +ErrorNumber93=638 +ErrorString93="Centering current exceeded (plane 3)" + + +[VacuumErrors] +ErrorNumber1=101 +ErrorString1="Data module error" +ErrorNumber2=201 +ErrorString2="Underflow of actual vacuum value" +ErrorNumber3=202 +ErrorString3="Overflow of actual vacuum value" +ErrorNumber4=301 +ErrorString4="Timeout vacuum" +ErrorNumber5=301 +ErrorString5="Timeout vacuum breakdown" +ErrorNumber6=401 +ErrorString6="Bad vacuum during X-ray on" + +[AxisErrors] +ErrorNumber0=1002 +ErrorString0="general EL_Critical" + +[ManiErrors] diff --git a/XP.Hardware.RaySource/ReleaseFiles/unins000.dat b/XP.Hardware.RaySource/ReleaseFiles/unins000.dat new file mode 100644 index 0000000..227c4d3 Binary files /dev/null and b/XP.Hardware.RaySource/ReleaseFiles/unins000.dat differ diff --git a/XP.Hardware.RaySource/Resources/Resources.Designer.cs b/XP.Hardware.RaySource/Resources/Resources.Designer.cs index 689e6f6..4e8793f 100644 --- a/XP.Hardware.RaySource/Resources/Resources.Designer.cs +++ b/XP.Hardware.RaySource/Resources/Resources.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // 此代码由工具生成。 // 运行时版本:4.0.30319.42000 @@ -19,7 +19,7 @@ namespace XP.Hardware.RaySource.Resources { // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -133,7 +133,7 @@ namespace XP.Hardware.RaySource.Resources { } /// - /// 查找类似 射线源配置 的本地化字符串。 + /// 查找类似 射线源高级选项 的本地化字符串。 /// internal static string RaySource_ConfigWindowTitle { get { @@ -604,7 +604,7 @@ namespace XP.Hardware.RaySource.Resources { /// /// 查找类似 射线源 - ///不可用 的本地化字符串。 + ///未连接 的本地化字符串。 /// internal static string RaySource_StatusUnavailable { get { @@ -855,6 +855,15 @@ namespace XP.Hardware.RaySource.Resources { } } + /// + /// 查找类似 射线 的本地化字符串。 + /// + internal static string RaySource_XRay { + get { + return ResourceManager.GetString("RaySource_XRay", resourceCulture); + } + } + /// /// 查找类似 关闭 的本地化字符串。 /// diff --git a/XP.Hardware.RaySource/Resources/Resources.en-US.resx b/XP.Hardware.RaySource/Resources/Resources.en-US.resx index cffa569..f93f57c 100644 --- a/XP.Hardware.RaySource/Resources/Resources.en-US.resx +++ b/XP.Hardware.RaySource/Resources/Resources.en-US.resx @@ -1,5 +1,64 @@ + @@ -179,7 +238,7 @@ Opened X-Ray -Unavailable +Not Connected Connect Ray Source @@ -215,7 +274,7 @@ Unavailable Config - X-Ray Source Configuration + X-Ray Source Advanced Options Warm-Up: @@ -244,8 +303,8 @@ Unavailable Normal - - X-Ray: + + X-Ray On @@ -334,4 +393,7 @@ Unavailable Operation command sent, waiting for device execution... + + X-Ray: + \ No newline at end of file diff --git a/XP.Hardware.RaySource/Resources/Resources.resx b/XP.Hardware.RaySource/Resources/Resources.resx index 2886a8a..20d7462 100644 --- a/XP.Hardware.RaySource/Resources/Resources.resx +++ b/XP.Hardware.RaySource/Resources/Resources.resx @@ -1,5 +1,64 @@ + @@ -190,7 +249,7 @@ 射线源 -不可用 +未连接 RaySourceOperateView - 射线源不可用状态文本 | X-Ray unavailable status text @@ -238,7 +297,7 @@ RaySourceOperateView - 配置按钮 | Config button - 射线源配置 + 射线源高级选项 RaySourceConfigWindow - 窗口标题 | Window title @@ -277,9 +336,8 @@ 正常 RaySourceConfigView - 连锁正常状态 | Interlock normal status - - 射线状态: - RaySourceConfigView - 射线开启状态标签 | X-ray on status label + + 射线 开启 @@ -383,4 +441,8 @@ 操作指令已发送,等待设备执行... + + 射线状态: + RaySourceConfigView - 射线开启状态标签 | X-ray on status label + \ No newline at end of file diff --git a/XP.Hardware.RaySource/Resources/Resources.zh-CN.resx b/XP.Hardware.RaySource/Resources/Resources.zh-CN.resx index acef58c..3166c7b 100644 --- a/XP.Hardware.RaySource/Resources/Resources.zh-CN.resx +++ b/XP.Hardware.RaySource/Resources/Resources.zh-CN.resx @@ -1,5 +1,64 @@ + @@ -179,7 +238,7 @@ 射线源 -不可用 +未连接 连接射线源 @@ -215,7 +274,7 @@ 配置 - 射线源配置 + 射线源高级选项 暖机: @@ -244,8 +303,8 @@ 正常 - - 射线状态: + + 射线源 开启 @@ -334,4 +393,7 @@ 操作指令已发送,等待设备执行... + + 射线状态: + \ No newline at end of file diff --git a/XP.Hardware.RaySource/Resources/Resources.zh-TW.resx b/XP.Hardware.RaySource/Resources/Resources.zh-TW.resx index 0667e23..9f499a3 100644 --- a/XP.Hardware.RaySource/Resources/Resources.zh-TW.resx +++ b/XP.Hardware.RaySource/Resources/Resources.zh-TW.resx @@ -1,5 +1,64 @@ + @@ -179,7 +238,7 @@ 射線源 -不可用 +未連線 連接射線源 @@ -215,7 +274,7 @@ 配置 - 射線源配置 + 射線源高級選項 暖機: @@ -244,8 +303,8 @@ 正常 - - 射線狀態: + + 射線源 開啟 @@ -334,4 +393,7 @@ 操作指令已發送,等待設備執行... + + 射線狀態: + \ No newline at end of file diff --git a/XP.Hardware.RaySource/Views/RaySourceOperateView.xaml b/XP.Hardware.RaySource/Views/RaySourceOperateView.xaml index 6af0097..2b85bf5 100644 --- a/XP.Hardware.RaySource/Views/RaySourceOperateView.xaml +++ b/XP.Hardware.RaySource/Views/RaySourceOperateView.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" x:Class="XP.Hardware.RaySource.Views.RaySourceOperateView" mc:Ignorable="d" d:DesignWidth="350" - prism:ViewModelLocator.AutoWireViewModel="True" Height="249" Background="White" > + prism:ViewModelLocator.AutoWireViewModel="True" Height="230" Background="White" > @@ -62,25 +62,43 @@ - - + + + + + + + + + + - + - + + CornerRadius="35"> + + + + + + + + + + + + diff --git a/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs b/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs index 8c1d4b3..8b101e1 100644 --- a/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs +++ b/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs @@ -19,6 +19,9 @@ namespace XP.ImageProcessing.RoiControl.Controls private const double ZoomStep = 1.2; private Adorner? currentAdorner; + /// 比例尺内侧竖向刻度线的 X 坐标(像素,相对尺身左端),仅画线不标数字。 + public ObservableCollection ScaleBarMinorTickXs { get; } = new(); + public PolygonRoiCanvas() { InitializeComponent(); @@ -42,6 +45,8 @@ namespace XP.ImageProcessing.RoiControl.Controls } } } + + RefreshScaleBar(); } private void ROIItems_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) @@ -123,7 +128,6 @@ namespace XP.ImageProcessing.RoiControl.Controls var control = (PolygonRoiCanvas)d; if (e.NewValue is BitmapSource bitmap) { - // 使用像素尺寸,避免 DPI 不同导致 DIP 尺寸与实际像素不一致 control.CanvasWidth = bitmap.PixelWidth; control.CanvasHeight = bitmap.PixelHeight; control.ResetView(); @@ -135,9 +139,16 @@ namespace XP.ImageProcessing.RoiControl.Controls control.ResetView(); } + // 图像切换时清除测量、叠加层和ROI + control.ClearMeasurements(); + control.ROIItems?.Clear(); + control.SelectedROI = null; + // 图像尺寸变化后刷新十字线 if (control.ShowCrosshair) control.AddCrosshair(); + + control.RefreshScaleBar(); } public static readonly DependencyProperty ROIItemsProperty = @@ -200,7 +211,7 @@ namespace XP.ImageProcessing.RoiControl.Controls public static readonly DependencyProperty CanvasWidthProperty = DependencyProperty.Register(nameof(CanvasWidth), typeof(double), typeof(PolygonRoiCanvas), - new PropertyMetadata(800.0)); + new PropertyMetadata(800.0, OnCanvasOrScaleBarParameterChanged)); public double CanvasWidth { @@ -210,7 +221,7 @@ namespace XP.ImageProcessing.RoiControl.Controls public static readonly DependencyProperty CanvasHeightProperty = DependencyProperty.Register(nameof(CanvasHeight), typeof(double), typeof(PolygonRoiCanvas), - new PropertyMetadata(600.0)); + new PropertyMetadata(600.0, OnCanvasOrScaleBarParameterChanged)); public double CanvasHeight { @@ -218,6 +229,116 @@ namespace XP.ImageProcessing.RoiControl.Controls set => SetValue(CanvasHeightProperty, value); } + /// 是否在图像上显示比例尺(叠在图像坐标系内,随缩放与平移移动)。 + public static readonly DependencyProperty ShowScaleBarProperty = + DependencyProperty.Register(nameof(ShowScaleBar), typeof(bool), typeof(PolygonRoiCanvas), + new PropertyMetadata(false, OnCanvasOrScaleBarParameterChanged)); + + public bool ShowScaleBar + { + get => (bool)GetValue(ShowScaleBarProperty); + set => SetValue(ShowScaleBarProperty, value); + } + + /// 单像素对应的物理长度(mm),用于比例尺刻度换算。 + public static readonly DependencyProperty ScaleBarMmPerPixelProperty = + DependencyProperty.Register(nameof(ScaleBarMmPerPixel), typeof(double), typeof(PolygonRoiCanvas), + new PropertyMetadata(0.139, OnCanvasOrScaleBarParameterChanged)); + + public double ScaleBarMmPerPixel + { + get => (double)GetValue(ScaleBarMmPerPixelProperty); + set => SetValue(ScaleBarMmPerPixelProperty, value); + } + + public static readonly DependencyProperty ScaleBarLengthPixelsProperty = + DependencyProperty.Register(nameof(ScaleBarLengthPixels), typeof(double), typeof(PolygonRoiCanvas), + new PropertyMetadata(100.0)); + + public double ScaleBarLengthPixels + { + get => (double)GetValue(ScaleBarLengthPixelsProperty); + private set => SetValue(ScaleBarLengthPixelsProperty, value); + } + + public static readonly DependencyProperty ScaleBarCaptionProperty = + DependencyProperty.Register(nameof(ScaleBarCaption), typeof(string), typeof(PolygonRoiCanvas), + new PropertyMetadata(string.Empty)); + + public string ScaleBarCaption + { + get => (string)GetValue(ScaleBarCaptionProperty); + private set => SetValue(ScaleBarCaptionProperty, value); + } + + private static void OnCanvasOrScaleBarParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((PolygonRoiCanvas)d).RefreshScaleBar(); + } + + /// 按图像宽度选取 1–2–5 标度,使比例尺约占画布宽度的约 22%。 + private void RefreshScaleBar() + { + const double targetFrac = 0.22; + const double maxFrac = 0.88; + const double minPx = 24.0; + + if (!ShowScaleBar || CanvasWidth < 16 || ScaleBarMmPerPixel <= 0 || double.IsNaN(ScaleBarMmPerPixel)) + { + ScaleBarLengthPixels = minPx; + ScaleBarCaption = string.Empty; + ScaleBarMinorTickXs.Clear(); + return; + } + + double maxPx = Math.Max(minPx, CanvasWidth * maxFrac); + double idealPx = Math.Min(CanvasWidth * targetFrac, maxPx); + double idealMm = idealPx * ScaleBarMmPerPixel; + double niceMm = RoundToNiceLengthMm(idealMm); + double barPx = niceMm / ScaleBarMmPerPixel; + + while (barPx > maxPx && niceMm > ScaleBarMmPerPixel * minPx * 1.5) + { + niceMm /= 2.0; + barPx = niceMm / ScaleBarMmPerPixel; + } + + while (barPx < minPx && niceMm < idealMm * 200) + { + niceMm *= 2.0; + barPx = niceMm / ScaleBarMmPerPixel; + } + + if (barPx < minPx) + barPx = minPx; + + ScaleBarLengthPixels = barPx; + ScaleBarCaption = FormatScaleBarCaptionMm(barPx * ScaleBarMmPerPixel); + + ScaleBarMinorTickXs.Clear(); + int divisions = barPx >= 120 ? 10 : barPx >= 60 ? 6 : 4; + for (int i = 1; i < divisions; i++) + ScaleBarMinorTickXs.Add(barPx * i / divisions); + } + + private static double RoundToNiceLengthMm(double mm) + { + if (mm <= 0 || double.IsNaN(mm) || double.IsInfinity(mm)) + return 0.1; + var magnitude = Math.Pow(10.0, Math.Floor(Math.Log10(mm))); + var normalized = mm / magnitude; + var nice = normalized < 1.5 ? 1.0 : normalized < 3.5 ? 2.0 : normalized < 7.5 ? 5.0 : 10.0; + return nice * magnitude; + } + + private static string FormatScaleBarCaptionMm(double mm) + { + if (mm >= 100) return $"{mm:F0} mm"; + if (mm >= 10) return $"{mm:F1} mm"; + if (mm >= 1) return $"{mm:F2} mm"; + return $"{mm:F3} mm"; + } + public static readonly DependencyProperty SelectedROIProperty = DependencyProperty.Register(nameof(SelectedROI), typeof(ROIShape), typeof(PolygonRoiCanvas), new PropertyMetadata(null, OnSelectedROIChanged)); @@ -295,6 +416,19 @@ namespace XP.ImageProcessing.RoiControl.Controls set => SetValue(ShowCrosshairProperty, value); } + // ── 光标信息(像素坐标 + 灰度值)── + + public static readonly DependencyProperty CursorInfoProperty = + DependencyProperty.Register(nameof(CursorInfo), typeof(string), typeof(PolygonRoiCanvas), + new PropertyMetadata("X: -- Y: -- Gray: --")); + + /// 鼠标在图像上的像素坐标和灰度值,格式: "X: 123 Y: 456 Gray: 128" + public string CursorInfo + { + get => (string)GetValue(CursorInfoProperty); + set => SetValue(CursorInfoProperty, value); + } + private Line _crosshairH, _crosshairV; private static void OnShowCrosshairChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) @@ -371,7 +505,7 @@ namespace XP.ImageProcessing.RoiControl.Controls private Ellipse _bgaPendingDot; // 气泡测量状态 - public enum BubbleSubTool { Roi, Wand, Brush, Eraser } + public enum BubbleSubTool { Roi, RoiCircle, RoiPolygon, Wand, Brush, Eraser } private BubbleSubTool _bubbleTool = BubbleSubTool.Roi; private Rectangle _bubbleRoiRect; private Ellipse _bubbleRoiHandle; // 右下角调整手柄 @@ -381,6 +515,17 @@ namespace XP.ImageProcessing.RoiControl.Controls private bool _bubbleRoiDragging; private bool _bubbleRoiMoving; // 拖动整个 ROI private bool _bubbleRoiResizing; // 右下角调整大小 + // 圆形 ROI + private Ellipse _bubbleCircleShape; + private Point? _bubbleCircleCenter; + private double _bubbleCircleRadius; + private bool _bubbleCircleDragging; + private bool _bubbleCircleMoving; // 拖动整个圆形 ROI + private bool _bubbleCircleResizing; // 调整圆形 ROI 大小 + private Point _bubbleCircleDragOffset; + // 多边形 ROI + private Polygon _bubblePolyShape; + private System.Collections.ObjectModel.ObservableCollection _bubblePolyPoints = new(); private Point _bubbleRoiDragOffset; private Image _bubbleMaskImage; private System.Windows.Media.Imaging.WriteableBitmap _bubbleMask; @@ -390,10 +535,39 @@ namespace XP.ImageProcessing.RoiControl.Controls private bool _bubbleBrushDragging; private readonly System.Collections.Generic.Stack _bubbleUndoStack = new(); - public void SetBubbleTool(BubbleSubTool tool) => _bubbleTool = tool; + public void SetBubbleTool(BubbleSubTool tool) + { + _bubbleTool = tool; + // 根据工具设置光标 + UpdateBubbleToolCursor(); + } + + private void UpdateBubbleToolCursor() + { + if (mainCanvas == null) return; + if (CurrentMeasureMode != Models.MeasureMode.BubbleMeasure) + { + mainCanvas.Cursor = Cursors.Arrow; + return; + } + mainCanvas.Cursor = _bubbleTool switch + { + BubbleSubTool.Wand => Cursors.Cross, + BubbleSubTool.Brush => Cursors.Pen, + BubbleSubTool.Eraser => Cursors.No, + _ => Cursors.Arrow + }; + } + public void SetBubbleThreshold(int val) => _bubbleThreshold = val; public void SetBubbleBrushSize(int val) => _bubbleBrushSize = val; public void SetBubbleVoidLimit(double val) { _bubbleVoidLimit = val; UpdateBubbleResult(); } + public void SetBubblePolyPoints(System.Collections.Generic.IList points) + { + _bubblePolyPoints.Clear(); + foreach (var p in points) _bubblePolyPoints.Add(p); + if (_bubblePolyPoints.Count >= 3) InitBubbleMask(); + } public Rect? BubbleRoi => _bubbleRoi; /// 设置 BGA 测量的气泡/焊球绘制模式 @@ -475,6 +649,7 @@ namespace XP.ImageProcessing.RoiControl.Controls _bubbleRoi = null; _bubbleRoiStart = null; _bubbleRoiDragging = false; _bubbleRoiMoving = false; _bubbleRoiResizing = false; _bubbleBrushDragging = false; + _bubbleCircleDragging = false; _bubbleCircleMoving = false; _bubbleCircleResizing = false; _bubbleTool = BubbleSubTool.Roi; _bubbleUndoStack.Clear(); // 清理外部叠加的结果图层(IsHitTestVisible=false 的 Image,排除背景图) @@ -545,13 +720,89 @@ namespace XP.ImageProcessing.RoiControl.Controls private Models.MeasureGroup CreatePPGroup(Point p1, Point p2) { var g = new Models.MeasureGroup { P1 = p1, P2 = p2 }; - g.Line = new Line { Stroke = Brushes.Lime, StrokeThickness = 2, IsHitTestVisible = false }; + g.Line = new Line { Stroke = Brushes.Lime, StrokeThickness = 1, IsHitTestVisible = false }; g.Label = new TextBlock { Foreground = Brushes.Yellow, FontSize = 13, FontWeight = FontWeights.Bold, IsHitTestVisible = false }; + + // 使用垂直线段代替圆点 + g.PerpLine1 = new Line { Stroke = Brushes.Yellow, StrokeThickness = 1, IsHitTestVisible = true, Cursor = Cursors.Hand }; + g.PerpLine2 = new Line { Stroke = Brushes.Yellow, StrokeThickness = 1, IsHitTestVisible = true, Cursor = Cursors.Hand }; + + // 保留圆点以兼容拖拽逻辑(但设为不可见) g.Dot1 = CreateMDot(Brushes.Red); g.Dot2 = CreateMDot(Brushes.Blue); - foreach (UIElement el in new UIElement[] { g.Line, g.Label, g.Dot1, g.Dot2 }) + g.Dot1.Visibility = Visibility.Collapsed; + g.Dot2.Visibility = Visibility.Collapsed; + + foreach (UIElement el in new UIElement[] { g.Line, g.Label, g.PerpLine1, g.PerpLine2, g.Dot1, g.Dot2 }) _measureOverlay.Children.Add(el); + + // 设置圆点位置(用于拖拽计算) SetDotPos(g.Dot1, p1); SetDotPos(g.Dot2, p2); + + // 垂直线段1的拖拽处理 - 直接设置拖拽状态 + g.PerpLine1.MouseLeftButtonDown += (s, e) => + { + _mDraggingOwner = g; + _mDraggingRole = "Dot1"; + _mDraggingDot = g.Dot1; + g.PerpLine1.CaptureMouse(); + e.Handled = true; + }; + g.PerpLine1.MouseMove += (s, e) => + { + if (_mDraggingOwner != g || _mDraggingRole != "Dot1" || _measureOverlay == null) return; + if (e.LeftButton != MouseButtonState.Pressed) return; + var pos = e.GetPosition(_measureOverlay); + SetDotPos(g.Dot1, pos); + g.P1 = pos; + g.UpdateLine(); + g.UpdateLabel(FormatDistance(g.Distance)); + RaiseMeasureCompleted(g.P1, g.P2, g.Distance, MeasureCount, "PointDistance"); + }; + g.PerpLine1.MouseLeftButtonUp += (s, e) => + { + if (_mDraggingOwner == g && _mDraggingRole == "Dot1") + { + _mDraggingOwner = null; + _mDraggingRole = null; + _mDraggingDot = null; + g.PerpLine1.ReleaseMouseCapture(); + } + e.Handled = true; + }; + + // 垂直线段2的拖拽处理 + g.PerpLine2.MouseLeftButtonDown += (s, e) => + { + _mDraggingOwner = g; + _mDraggingRole = "Dot2"; + _mDraggingDot = g.Dot2; + g.PerpLine2.CaptureMouse(); + e.Handled = true; + }; + g.PerpLine2.MouseMove += (s, e) => + { + if (_mDraggingOwner != g || _mDraggingRole != "Dot2" || _measureOverlay == null) return; + if (e.LeftButton != MouseButtonState.Pressed) return; + var pos = e.GetPosition(_measureOverlay); + SetDotPos(g.Dot2, pos); + g.P2 = pos; + g.UpdateLine(); + g.UpdateLabel(FormatDistance(g.Distance)); + RaiseMeasureCompleted(g.P1, g.P2, g.Distance, MeasureCount, "PointDistance"); + }; + g.PerpLine2.MouseLeftButtonUp += (s, e) => + { + if (_mDraggingOwner == g && _mDraggingRole == "Dot2") + { + _mDraggingOwner = null; + _mDraggingRole = null; + _mDraggingDot = null; + g.PerpLine2.ReleaseMouseCapture(); + } + e.Handled = true; + }; + g.UpdateLine(); g.UpdateLabel(FormatDistance(g.Distance)); return g; } @@ -576,7 +827,7 @@ namespace XP.ImageProcessing.RoiControl.Controls _ptlTempDot2 = CreateMDot(Brushes.Lime); _measureOverlay.Children.Add(_ptlTempDot2); SetDotPos(_ptlTempDot2, pos); - _ptlTempLine = new Line { Stroke = Brushes.Lime, StrokeThickness = 2, IsHitTestVisible = false, + _ptlTempLine = new Line { Stroke = Brushes.Lime, StrokeThickness = 1, IsHitTestVisible = false, X1 = _ptlTempL1.Value.X, Y1 = _ptlTempL1.Value.Y, X2 = pos.X, Y2 = pos.Y }; _measureOverlay.Children.Add(_ptlTempLine); RaiseMeasureStatusChanged($"点线距 - 直线已定义,请点击测量点"); @@ -602,12 +853,12 @@ namespace XP.ImageProcessing.RoiControl.Controls private Models.PointToLineGroup CreatePTLGroup(Point l1, Point l2, Point p) { var g = new Models.PointToLineGroup { L1 = l1, L2 = l2, P = p }; - g.MainLine = new Line { Stroke = Brushes.Lime, StrokeThickness = 2, IsHitTestVisible = false }; + g.MainLine = new Line { Stroke = Brushes.Lime, StrokeThickness = 1, IsHitTestVisible = false }; g.ExtLine = new Line { Stroke = Brushes.Lime, StrokeThickness = 1, IsHitTestVisible = false, StrokeDashArray = new DoubleCollection { 4, 2 }, Visibility = Visibility.Collapsed }; g.PerpLine = new Line { Stroke = Brushes.Yellow, StrokeThickness = 1, IsHitTestVisible = false, StrokeDashArray = new DoubleCollection { 4, 2 } }; - g.FootDot = new Ellipse { Width = 8, Height = 8, Fill = Brushes.Cyan, Stroke = Brushes.White, StrokeThickness = 1, IsHitTestVisible = false }; + g.FootDot = new Ellipse { Width = 2, Height = 2, Fill = Brushes.Cyan, Stroke = Brushes.White, StrokeThickness = 0.5, IsHitTestVisible = false }; g.Label = new TextBlock { Foreground = Brushes.Yellow, FontSize = 13, FontWeight = FontWeights.Bold, IsHitTestVisible = false }; g.DotL1 = CreateMDot(Brushes.Lime); g.DotL2 = CreateMDot(Brushes.Lime); @@ -709,7 +960,7 @@ namespace XP.ImageProcessing.RoiControl.Controls g.PathE4 = CreateEllipsePath(Brushes.Lime, false); g.FullLine = new Line { Stroke = Brushes.Red, StrokeThickness = 1, IsHitTestVisible = false }; - g.FillLine = new Line { Stroke = Brushes.Lime, StrokeThickness = 2, IsHitTestVisible = false }; + g.FillLine = new Line { Stroke = Brushes.Lime, StrokeThickness = 1, IsHitTestVisible = false }; g.Label = new TextBlock { FontSize = 13, FontWeight = FontWeights.Bold, Cursor = Cursors.Hand }; g.Label.SetValue(ContextMenuService.IsEnabledProperty, false); @@ -737,7 +988,7 @@ namespace XP.ImageProcessing.RoiControl.Controls private Ellipse CreateAxisHandle(Brush fill) { - var h = new Ellipse { Width = 8, Height = 8, Fill = fill, Stroke = Brushes.White, StrokeThickness = 1, Cursor = Cursors.SizeAll }; + var h = new Ellipse { Width = 2, Height = 2, Fill = fill, Stroke = Brushes.White, StrokeThickness = 0.5, Cursor = Cursors.SizeAll }; h.SetValue(ContextMenuService.IsEnabledProperty, false); h.MouseLeftButtonDown += MDot_Down; h.MouseMove += MDot_Move; @@ -838,7 +1089,7 @@ namespace XP.ImageProcessing.RoiControl.Controls }; c.CenterDot = CreateMDot(isBall ? Brushes.Lime : Brushes.Orange); c.EdgeDot = CreateMDot(isBall ? Brushes.Lime : Brushes.Orange); - c.EdgeDot.Width = 8; c.EdgeDot.Height = 8; + c.EdgeDot.Width = 2; c.EdgeDot.Height = 2; c.EdgeDot.Cursor = System.Windows.Input.Cursors.SizeAll; _measureOverlay.Children.Add(c.Shape); @@ -902,7 +1153,7 @@ namespace XP.ImageProcessing.RoiControl.Controls private Ellipse CreateMDot(Brush fill) { - var dot = new Ellipse { Width = 12, Height = 12, Fill = fill, Stroke = Brushes.White, StrokeThickness = 1.5, Cursor = Cursors.Hand }; + var dot = new Ellipse { Width = 2, Height = 2, Fill = fill, Stroke = Brushes.White, StrokeThickness = 0.5, Cursor = Cursors.Hand }; dot.SetValue(ContextMenuService.IsEnabledProperty, false); dot.MouseLeftButtonDown += MDot_Down; dot.MouseMove += MDot_Move; @@ -1154,6 +1405,64 @@ namespace XP.ImageProcessing.RoiControl.Controls // ── 气泡测量辅助 ── + /// 是否已有任何形状的气泡 ROI + private bool HasBubbleRoi => + _bubbleRoi.HasValue || _bubbleCircleCenter.HasValue || _bubblePolyPoints.Count >= 3; + + /// 判断点是否在当前气泡 ROI 内 + private bool IsInBubbleRoi(Point pos) + { + if (_bubbleRoi.HasValue) + return _bubbleRoi.Value.Contains(pos); + if (_bubbleCircleCenter.HasValue) + { + double dx = pos.X - _bubbleCircleCenter.Value.X; + double dy = pos.Y - _bubbleCircleCenter.Value.Y; + return dx * dx + dy * dy <= _bubbleCircleRadius * _bubbleCircleRadius; + } + if (_bubblePolyPoints.Count >= 3) + return IsPointInPolygon(pos, _bubblePolyPoints); + return false; + } + + private static bool IsPointInPolygon(Point p, System.Collections.Generic.IList polygon) + { + bool inside = false; + int n = polygon.Count; + for (int i = 0, j = n - 1; i < n; j = i++) + { + if ((polygon[i].Y > p.Y) != (polygon[j].Y > p.Y) && + p.X < (polygon[j].X - polygon[i].X) * (p.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) + polygon[i].X) + inside = !inside; + } + return inside; + } + + /// 获取当前 ROI 的外接矩形(用于掩码计算范围) + private Rect GetBubbleRoiBounds() + { + if (_bubbleRoi.HasValue) return _bubbleRoi.Value; + if (_bubbleCircleCenter.HasValue) + { + var c = _bubbleCircleCenter.Value; + var r = _bubbleCircleRadius; + return new Rect(c.X - r, c.Y - r, r * 2, r * 2); + } + if (_bubblePolyPoints.Count >= 3) + { + double minX = double.MaxValue, minY = double.MaxValue, maxX = double.MinValue, maxY = double.MinValue; + foreach (var pt in _bubblePolyPoints) + { + if (pt.X < minX) minX = pt.X; + if (pt.Y < minY) minY = pt.Y; + if (pt.X > maxX) maxX = pt.X; + if (pt.Y > maxY) maxY = pt.Y; + } + return new Rect(minX, minY, maxX - minX, maxY - minY); + } + return Rect.Empty; + } + private void EnsureBubbleRoiVisuals() { EnsureMeasureOverlay(); @@ -1162,7 +1471,7 @@ namespace XP.ImageProcessing.RoiControl.Controls _bubbleRoiRect = new Rectangle { Stroke = Brushes.Red, - StrokeThickness = 1.5, + StrokeThickness = 1, Fill = Brushes.Transparent, Visibility = Visibility.Collapsed, IsHitTestVisible = false @@ -1211,9 +1520,55 @@ namespace XP.ImageProcessing.RoiControl.Controls } } + private void EnsureBubbleCircleVisuals() + { + EnsureMeasureOverlay(); + if (_bubbleCircleShape == null) + { + _bubbleCircleShape = new Ellipse + { + Stroke = Brushes.Red, + StrokeThickness = 1, + Fill = Brushes.Transparent, + Visibility = Visibility.Collapsed, + IsHitTestVisible = false + }; + _measureOverlay.Children.Add(_bubbleCircleShape); + } + } + + private void UpdateBubbleCircleVisuals() + { + if (_bubbleCircleShape == null || !_bubbleCircleCenter.HasValue) return; + var c = _bubbleCircleCenter.Value; + var r = _bubbleCircleRadius; + _bubbleCircleShape.Width = r * 2; + _bubbleCircleShape.Height = r * 2; + Canvas.SetLeft(_bubbleCircleShape, c.X - r); + Canvas.SetTop(_bubbleCircleShape, c.Y - r); + _bubbleCircleShape.Visibility = Visibility.Visible; + } + + private void UpdateBubblePolyVisuals() + { + EnsureMeasureOverlay(); + if (_bubblePolyShape == null) + { + _bubblePolyShape = new Polygon + { + Stroke = Brushes.Red, + StrokeThickness = 1, + Fill = Brushes.Transparent, + IsHitTestVisible = false + }; + _measureOverlay.Children.Add(_bubblePolyShape); + } + _bubblePolyShape.Points = new PointCollection(_bubblePolyPoints); + } + private void InitBubbleMask() { - if (!_bubbleRoi.HasValue) return; + if (!HasBubbleRoi) return; int w = (int)CanvasWidth, h = (int)CanvasHeight; if (w <= 0 || h <= 0) return; @@ -1238,9 +1593,9 @@ namespace XP.ImageProcessing.RoiControl.Controls private void ApplyBrushAt(Point pos) { - if (_bubbleMask == null || !_bubbleRoi.HasValue) return; + if (_bubbleMask == null || !HasBubbleRoi) return; - var roi = _bubbleRoi.Value; + var roi = GetBubbleRoiBounds(); int w = _bubbleMask.PixelWidth, h = _bubbleMask.PixelHeight; int cx = (int)pos.X, cy = (int)pos.Y; int r = _bubbleBrushSize; @@ -1249,15 +1604,12 @@ namespace XP.ImageProcessing.RoiControl.Controls int roiX0 = Math.Max(0, (int)roi.X), roiY0 = Math.Max(0, (int)roi.Y); int roiX1 = Math.Min(w, (int)roi.Right), roiY1 = Math.Min(h, (int)roi.Bottom); - // 计算笔刷影响的矩形区域 int x0 = Math.Max(roiX0, cx - r), y0 = Math.Max(roiY0, cy - r); int x1 = Math.Min(roiX1, cx + r + 1), y1 = Math.Min(roiY1, cy + r + 1); if (x0 >= x1 || y0 >= y1) return; int regionW = x1 - x0, regionH = y1 - y0; - int stride = w * 4; - // 读取整行范围的像素 var pixels = new byte[regionW * regionH * 4]; _bubbleMask.CopyPixels(new System.Windows.Int32Rect(x0, y0, regionW, regionH), pixels, regionW * 4, 0); @@ -1268,6 +1620,8 @@ namespace XP.ImageProcessing.RoiControl.Controls { int dx = px2 - cx, dy = py2 - cy; if (dx * dx + dy * dy > r2) continue; + // 检查是否在 ROI 内 + if (!IsInBubbleRoi(new Point(px2, py2))) continue; int idx = ((py2 - y0) * regionW + (px2 - x0)) * 4; if (erase) @@ -1290,8 +1644,8 @@ namespace XP.ImageProcessing.RoiControl.Controls private void UpdateBubbleResult() { - if (_bubbleMask == null || !_bubbleRoi.HasValue) return; - var roi = _bubbleRoi.Value; + if (_bubbleMask == null || !HasBubbleRoi) return; + var roi = GetBubbleRoiBounds(); int w = _bubbleMask.PixelWidth, h = _bubbleMask.PixelHeight; int stride = w * 4; var pixels = new byte[stride * h]; @@ -1304,13 +1658,13 @@ namespace XP.ImageProcessing.RoiControl.Controls for (int y = roiY0; y < roiY1; y++) for (int x = roiX0; x < roiX1; x++) { + if (!IsInBubbleRoi(new Point(x, y))) continue; roiArea++; int idx = (y * w + x) * 4; - if (pixels[idx + 3] > 0) voidArea++; // alpha > 0 表示已标记 + if (pixels[idx + 3] > 0) voidArea++; } double voidRate = roiArea > 0 ? voidArea * 100.0 / roiArea : 0; - // 更新 ROI 上方标签 if (_bubbleResultLabel != null) { string cls = voidRate <= _bubbleVoidLimit ? "PASS" : "FAIL"; @@ -1327,14 +1681,15 @@ namespace XP.ImageProcessing.RoiControl.Controls /// 魔棒:在点击位置做 flood fill public void WandFloodFill(Point pos) { - if (_bubbleMask == null || !_bubbleRoi.HasValue || ImageSource == null) return; + if (_bubbleMask == null || !HasBubbleRoi || ImageSource == null) return; // 保存快照用于撤销 SaveMaskSnapshot(); - var roi = _bubbleRoi.Value; + if (!IsInBubbleRoi(pos)) return; + + var roi = GetBubbleRoiBounds(); int px = (int)pos.X, py = (int)pos.Y; - if (!roi.Contains(pos)) return; // 获取灰度像素 var gray = GetGrayscalePixels(); @@ -1344,9 +1699,8 @@ namespace XP.ImageProcessing.RoiControl.Controls if (px < 0 || px >= w || py < 0 || py >= h) return; int seedVal = gray[py * w + px]; - int lo = _bubbleThreshold, hi = _bubbleThreshold; + int lo = _bubbleThreshold; - // BFS flood fill var visited = new bool[w * h]; var queue = new System.Collections.Generic.Queue<(int x, int y)>(); queue.Enqueue((px, py)); @@ -1362,19 +1716,16 @@ namespace XP.ImageProcessing.RoiControl.Controls var (cx, cy) = queue.Dequeue(); int val = gray[cy * w + cx]; - // 阈值判断:与种子点灰度差在阈值范围内 if (Math.Abs(val - seedVal) > lo) continue; - // 必须在 ROI 内 - if (cx < roiX0 || cx >= roiX1 || cy < roiY0 || cy >= roiY1) continue; + if (!IsInBubbleRoi(new Point(cx, cy))) continue; filled.Add((cx, cy)); - // 四邻域 int[] dx = { -1, 1, 0, 0 }, dy = { 0, 0, -1, 1 }; for (int d = 0; d < 4; d++) { int nx = cx + dx[d], ny = cy + dy[d]; - if (nx >= roiX0 && nx < roiX1 && ny >= roiY0 && ny < roiY1 && !visited[ny * w + nx]) + if (nx >= 0 && nx < w && ny >= 0 && ny < h && !visited[ny * w + nx] && IsInBubbleRoi(new Point(nx, ny))) { visited[ny * w + nx] = true; queue.Enqueue((nx, ny)); @@ -1455,8 +1806,16 @@ namespace XP.ImageProcessing.RoiControl.Controls if (_bubbleRoiHandle != null) { _measureOverlay.Children.Remove(_bubbleRoiHandle); _bubbleRoiHandle = null; } if (_bubbleResultLabel != null) { _measureOverlay.Children.Remove(_bubbleResultLabel); _bubbleResultLabel = null; } if (_bubbleMaskImage != null) { _measureOverlay.Children.Remove(_bubbleMaskImage); _bubbleMaskImage = null; } + if (_bubbleCircleShape != null) { _measureOverlay.Children.Remove(_bubbleCircleShape); _bubbleCircleShape = null; } + if (_bubblePolyShape != null) { _measureOverlay.Children.Remove(_bubblePolyShape); _bubblePolyShape = null; } } _bubbleRoi = null; + _bubbleCircleCenter = null; + _bubbleCircleRadius = 0; + _bubbleCircleDragging = false; + _bubbleCircleMoving = false; + _bubbleCircleResizing = false; + _bubblePolyPoints.Clear(); _bubbleMask = null; _bubbleRoiStart = null; _bubbleRoiDragging = false; @@ -1735,6 +2094,38 @@ namespace XP.ImageProcessing.RoiControl.Controls #region Mouse Events + private void UpdateCursorInfo(Point pos) + { + if (ImageSource == null) + { + CursorInfo = "X: -- Y: -- Gray: --"; + return; + } + + int px = (int)pos.X, py = (int)pos.Y; + string grayText = "--"; + + if (ImageSource is BitmapSource bmp && px >= 0 && py >= 0 && px < bmp.PixelWidth && py < bmp.PixelHeight) + { + try + { + var pixel = new byte[4]; + var converted = new FormatConvertedBitmap(bmp, PixelFormats.Bgra32, null, 0); + converted.CopyPixels(new System.Windows.Int32Rect(px, py, 1, 1), pixel, 4, 0); + int gray = (int)(pixel[2] * 0.299 + pixel[1] * 0.587 + pixel[0] * 0.114); + grayText = gray.ToString(); + } + catch { } + } + + CursorInfo = $"X: {px} Y: {py} Gray: {grayText}"; + } + + private void Canvas_MouseLeave(object sender, MouseEventArgs e) + { + CursorInfo = "X: -- Y: -- Gray: --"; + } + private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e) { double oldZoom = ZoomScale; @@ -1781,7 +2172,7 @@ namespace XP.ImageProcessing.RoiControl.Controls e.Handled = true; return; } - // 没有 ROI 时才画新的,有 ROI 时点击外部不拦截(让图像正常拖动) + // 没有 ROI 时才画新的 if (!_bubbleRoi.HasValue) { _bubbleRoiStart = pos; @@ -1791,12 +2182,52 @@ namespace XP.ImageProcessing.RoiControl.Controls e.Handled = true; return; } - // 有 ROI 但点击了外部 → 不拦截,走正常拖动逻辑 } - if ((_bubbleTool == BubbleSubTool.Brush || _bubbleTool == BubbleSubTool.Eraser) && _bubbleRoi.HasValue) + if (_bubbleTool == BubbleSubTool.RoiCircle) { - // 只在 ROI 内才启动画笔,ROI 外不拦截,让图像正常拖动 - if (_bubbleRoi.Value.Contains(pos)) + // 检查是否点击了圆形 ROI + if (_bubbleCircleCenter.HasValue) + { + double dx = pos.X - _bubbleCircleCenter.Value.X; + double dy = pos.Y - _bubbleCircleCenter.Value.Y; + double dist = Math.Sqrt(dx * dx + dy * dy); + // 先检查是否点击圆内部(拖动),排除边缘附近区域 + if (dist < _bubbleCircleRadius - 10) + { + _bubbleCircleMoving = true; + _bubbleCircleDragOffset = new Point(pos.X - _bubbleCircleCenter.Value.X, pos.Y - _bubbleCircleCenter.Value.Y); + mainCanvas.CaptureMouse(); + e.Handled = true; + return; + } + // 再检查是否点击边缘附近(调整大小) + if (Math.Abs(dist - _bubbleCircleRadius) < 15) + { + _bubbleCircleResizing = true; + _bubbleRoiStart = pos; + mainCanvas.CaptureMouse(); + e.Handled = true; + return; + } + } + // 没有圆形 ROI 时开始画 + if (!_bubbleCircleCenter.HasValue) + { + _bubbleRoiStart = pos; + _bubbleCircleDragging = true; + EnsureBubbleCircleVisuals(); + mainCanvas.CaptureMouse(); + e.Handled = true; + return; + } + } + if (_bubbleTool == BubbleSubTool.RoiPolygon) + { + // 多边形 ROI 由外部面板通过 CanvasClickedEvent 处理,这里不拦截 + } + if ((_bubbleTool == BubbleSubTool.Brush || _bubbleTool == BubbleSubTool.Eraser) && HasBubbleRoi) + { + if (IsInBubbleRoi(pos)) { SaveMaskSnapshot(); _bubbleBrushDragging = true; @@ -1855,8 +2286,47 @@ namespace XP.ImageProcessing.RoiControl.Controls e.Handled = true; return; } + // 气泡测量:圆形 ROI 拖拽 + if (_bubbleCircleDragging && _bubbleRoiStart.HasValue) + { + var pos = e.GetPosition(mainCanvas); + double dx = pos.X - _bubbleRoiStart.Value.X; + double dy = pos.Y - _bubbleRoiStart.Value.Y; + double r = Math.Sqrt(dx * dx + dy * dy); + if (_bubbleCircleShape != null) + { + _bubbleCircleShape.Width = r * 2; + _bubbleCircleShape.Height = r * 2; + Canvas.SetLeft(_bubbleCircleShape, _bubbleRoiStart.Value.X - r); + Canvas.SetTop(_bubbleCircleShape, _bubbleRoiStart.Value.Y - r); + _bubbleCircleShape.Visibility = Visibility.Visible; + } + e.Handled = true; + return; + } + // 气泡测量:圆形 ROI 拖动 + if (_bubbleCircleMoving && _bubbleCircleCenter.HasValue) + { + var pos = e.GetPosition(mainCanvas); + _bubbleCircleCenter = new Point(pos.X - _bubbleCircleDragOffset.X, pos.Y - _bubbleCircleDragOffset.Y); + UpdateBubbleCircleVisuals(); + e.Handled = true; + return; + } + // 气泡测量:圆形 ROI 调整大小 + if (_bubbleCircleResizing && _bubbleCircleCenter.HasValue) + { + var pos = e.GetPosition(mainCanvas); + double dx = pos.X - _bubbleCircleCenter.Value.X; + double dy = pos.Y - _bubbleCircleCenter.Value.Y; + _bubbleCircleRadius = Math.Max(5, Math.Sqrt(dx * dx + dy * dy)); + UpdateBubbleCircleVisuals(); + InitBubbleMask(); + e.Handled = true; + return; + } // 气泡测量:画笔/橡皮拖拽 - if (_bubbleBrushDragging && _bubbleRoi.HasValue) + if (_bubbleBrushDragging && HasBubbleRoi) { var pos = e.GetPosition(mainCanvas); ApplyBrushAt(pos); @@ -1877,6 +2347,9 @@ namespace XP.ImageProcessing.RoiControl.Controls lastMousePosition = currentPosition; } } + + // 更新光标信息(像素坐标 + 灰度值) + UpdateCursorInfo(e.GetPosition(mainCanvas)); } private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) @@ -1914,6 +2387,47 @@ namespace XP.ImageProcessing.RoiControl.Controls e.Handled = true; return; } + // 气泡测量:圆形 ROI 拖拽完成 + if (_bubbleCircleDragging && _bubbleRoiStart.HasValue) + { + var pos = e.GetPosition(mainCanvas); + double dx = pos.X - _bubbleRoiStart.Value.X; + double dy = pos.Y - _bubbleRoiStart.Value.Y; + double r = Math.Sqrt(dx * dx + dy * dy); + _bubbleCircleDragging = false; + mainCanvas.ReleaseMouseCapture(); + + if (r > 5) + { + _bubbleCircleCenter = _bubbleRoiStart.Value; + _bubbleCircleRadius = r; + _bubbleRoiStart = null; + InitBubbleMask(); + RaiseMeasureStatusChanged($"圆形ROI 已设置: 半径={r:F0}px"); + } + e.Handled = true; + return; + } + // 气泡测量:圆形 ROI 拖动完成 + if (_bubbleCircleMoving) + { + _bubbleCircleMoving = false; + mainCanvas.ReleaseMouseCapture(); + InitBubbleMask(); + e.Handled = true; + return; + } + // 气泡测量:圆形 ROI 调整大小完成 + if (_bubbleCircleResizing) + { + _bubbleCircleResizing = false; + _bubbleRoiStart = null; + mainCanvas.ReleaseMouseCapture(); + InitBubbleMask(); + RaiseMeasureStatusChanged($"圆形ROI 已调整: 半径={_bubbleCircleRadius:F0}px"); + e.Handled = true; + return; + } // 气泡测量:画笔/橡皮松开 if (_bubbleBrushDragging) { @@ -1933,7 +2447,7 @@ namespace XP.ImageProcessing.RoiControl.Controls { HandleMeasureClick(clickPosition); // 魔棒点击 - if (CurrentMeasureMode == Models.MeasureMode.BubbleMeasure && _bubbleTool == BubbleSubTool.Wand && _bubbleRoi.HasValue) + if (CurrentMeasureMode == Models.MeasureMode.BubbleMeasure && _bubbleTool == BubbleSubTool.Wand && HasBubbleRoi) { WandFloodFill(clickPosition); } diff --git a/XP.ImageProcessing.RoiControl/Models/MeasureGroup.cs b/XP.ImageProcessing.RoiControl/Models/MeasureGroup.cs index 32ba2aa..0c93043 100644 --- a/XP.ImageProcessing.RoiControl/Models/MeasureGroup.cs +++ b/XP.ImageProcessing.RoiControl/Models/MeasureGroup.cs @@ -9,12 +9,21 @@ namespace XP.ImageProcessing.RoiControl.Models /// 一次点点距测量的所有视觉元素 public class MeasureGroup { + // 保留原有圆点属性以兼容其他代码 public Ellipse Dot1 { get; set; } public Ellipse Dot2 { get; set; } + + // 新增:垂直线段(替代圆点的视觉表现) + public Line PerpLine1 { get; set; } + public Line PerpLine2 { get; set; } + public Line Line { get; set; } public TextBlock Label { get; set; } public Point P1 { get; set; } public Point P2 { get; set; } + + /// 垂直线段长度(像素) + public double PerpLineLength { get; set; } = 10.0; public double Distance { @@ -30,6 +39,46 @@ namespace XP.ImageProcessing.RoiControl.Models Line.X1 = P1.X; Line.Y1 = P1.Y; Line.X2 = P2.X; Line.Y2 = P2.Y; Line.Visibility = Visibility.Visible; + + // 更新垂直线段位置 + UpdatePerpLines(); + } + + /// 更新两条垂直线段的位置 + public void UpdatePerpLines() + { + if (PerpLine1 == null || PerpLine2 == null) return; + + // 计算两点连线的方向向量 + double dx = P2.X - P1.X; + double dy = P2.Y - P1.Y; + double len = Math.Sqrt(dx * dx + dy * dy); + + if (len < 0.001) return; // 避免除零 + + // 归一化方向向量 + double ux = dx / len; + double uy = dy / len; + + // 垂直方向向量 (-uy, ux) + double vx = -uy; + double vy = ux; + + // P1处的垂直线段 + double halfLen1 = PerpLineLength / 2; + PerpLine1.X1 = P1.X + vx * halfLen1; + PerpLine1.Y1 = P1.Y + vy * halfLen1; + PerpLine1.X2 = P1.X - vx * halfLen1; + PerpLine1.Y2 = P1.Y - vy * halfLen1; + PerpLine1.Visibility = Visibility.Visible; + + // P2处的垂直线段 + double halfLen2 = PerpLineLength / 2; + PerpLine2.X1 = P2.X + vx * halfLen2; + PerpLine2.Y1 = P2.Y + vy * halfLen2; + PerpLine2.X2 = P2.X - vx * halfLen2; + PerpLine2.Y2 = P2.Y - vy * halfLen2; + PerpLine2.Visibility = Visibility.Visible; } public void UpdateLabel(string distanceText = null) diff --git a/XP.ReportEngine/Configs/ConfigLoader.cs b/XP.ReportEngine/Configs/ConfigLoader.cs new file mode 100644 index 0000000..d2516cd --- /dev/null +++ b/XP.ReportEngine/Configs/ConfigLoader.cs @@ -0,0 +1,221 @@ +using System; +using System.Configuration; +using System.IO; +using XP.Common.Logging.Interfaces; + +namespace XP.ReportEngine.Configs +{ + /// + /// 报告引擎配置加载器(读取 App.config)| Report engine configuration loader (reads from App.config) + /// + public class ConfigLoader + { + private readonly ILoggerService _logger; + + /// + /// 构造函数 | Constructor + /// + /// 日志服务 | Logger service + public ConfigLoader(ILoggerService logger) + { + _logger = logger.ForModule(); + } + + /// + /// 从 App.config 加载报告引擎配置 | Load report engine configuration from App.config + /// + /// 配置前缀,默认为 "Report" | Configuration prefix, default is "Report" + /// 报告配置对象 | Report configuration object + public ReportConfig LoadReportConfig(string prefix = "Report") + { + try + { + _logger.Info("开始从 App.config 加载报告引擎配置,前缀: {Prefix} | Loading report config from App.config, prefix: {Prefix}", prefix); + + var config = new ReportConfig(); + + // 读取输出目录 | Read output directory + var outputDirectory = ConfigurationManager.AppSettings[$"{prefix}:OutputDirectory"]; + if (!string.IsNullOrEmpty(outputDirectory)) + { + config.OutputDirectory = outputDirectory; + } + + // 读取模板路径 | Read template path + var templatePath = ConfigurationManager.AppSettings[$"{prefix}:TemplatePath"]; + if (!string.IsNullOrEmpty(templatePath)) + { + config.TemplatePath = templatePath; + } + + // 读取文件名模式 | Read file name pattern + var fileNamePattern = ConfigurationManager.AppSettings[$"{prefix}:FileNamePattern"]; + if (!string.IsNullOrEmpty(fileNamePattern)) + { + config.FileNamePattern = fileNamePattern; + } + + // 读取重复文件名自动累加设置 | Read auto-increment on duplicate setting + var autoIncrement = ConfigurationManager.AppSettings[$"{prefix}:AutoIncrementOnDuplicate"]; + if (bool.TryParse(autoIncrement, out var autoIncrementValue)) + { + config.AutoIncrementOnDuplicate = autoIncrementValue; + } + + // 读取自动打开设置 | Read auto-open setting + var autoOpen = ConfigurationManager.AppSettings[$"{prefix}:AutoOpenAfterGenerate"]; + if (bool.TryParse(autoOpen, out var autoOpenValue)) + { + config.AutoOpenAfterGenerate = autoOpenValue; + } + + // 读取页面尺寸 | Read page size + var pageSize = ConfigurationManager.AppSettings[$"{prefix}:DefaultPageSize"]; + if (!string.IsNullOrEmpty(pageSize)) + { + config.DefaultPageSize = pageSize; + } + + // 读取页面方向 | Read page orientation + var orientation = ConfigurationManager.AppSettings[$"{prefix}:DefaultOrientation"]; + if (!string.IsNullOrEmpty(orientation)) + { + config.DefaultOrientation = orientation; + } + + // 读取边距配置 | Read margin configuration + var marginTop = ConfigurationManager.AppSettings[$"{prefix}:MarginTop"]; + if (float.TryParse(marginTop, out var marginTopValue)) + { + config.MarginTop = marginTopValue; + } + + var marginBottom = ConfigurationManager.AppSettings[$"{prefix}:MarginBottom"]; + if (float.TryParse(marginBottom, out var marginBottomValue)) + { + config.MarginBottom = marginBottomValue; + } + + var marginLeft = ConfigurationManager.AppSettings[$"{prefix}:MarginLeft"]; + if (float.TryParse(marginLeft, out var marginLeftValue)) + { + config.MarginLeft = marginLeftValue; + } + + var marginRight = ConfigurationManager.AppSettings[$"{prefix}:MarginRight"]; + if (float.TryParse(marginRight, out var marginRightValue)) + { + config.MarginRight = marginRightValue; + } + + // 读取公司名称 | Read company name + var companyName = ConfigurationManager.AppSettings[$"{prefix}:CompanyName"]; + if (!string.IsNullOrEmpty(companyName)) + { + config.CompanyName = companyName; + } + + // 读取公司 Logo 路径 | Read company logo path + var companyLogo = ConfigurationManager.AppSettings[$"{prefix}:CompanyLogo"]; + if (!string.IsNullOrEmpty(companyLogo)) + { + config.CompanyLogo = companyLogo; + } + + // 读取软件名称 | Read software name + var softwareName = ConfigurationManager.AppSettings[$"{prefix}:SoftwareName"]; + if (!string.IsNullOrEmpty(softwareName)) + { + config.SoftwareName = softwareName; + } + + // 读取软件 Logo 路径 | Read software logo path + var softwareLogo = ConfigurationManager.AppSettings[$"{prefix}:SoftwareLogo"]; + if (!string.IsNullOrEmpty(softwareLogo)) + { + config.SoftwareLogo = softwareLogo; + } + + // 验证配置 | Validate configuration + ValidateConfig(config); + + _logger.Info("报告引擎配置加载成功:输出目录={OutputDir}, 模板={Template} | Report config loaded: OutputDir={OutputDir}, Template={Template}", + config.OutputDirectory, config.TemplatePath); + + return config; + } + catch (Exception ex) + { + _logger.Warn("加载报告引擎配置失败,使用默认配置 | Failed to load report config, using defaults: {Message}", ex.Message); + return new ReportConfig(); + } + } + + /// + /// 验证配置参数 | Validate configuration parameters + /// + /// 报告配置对象 | Report configuration object + private void ValidateConfig(ReportConfig config) + { + // 验证输出目录(不存在则尝试创建)| Validate output directory (create if not exists) + if (string.IsNullOrWhiteSpace(config.OutputDirectory)) + { + _logger.Warn("OutputDirectory 为空,使用默认值 | OutputDirectory is empty, using default"); + config.OutputDirectory = new ReportConfig().OutputDirectory; + } + + // 验证模板路径 | Validate template path + if (string.IsNullOrWhiteSpace(config.TemplatePath)) + { + _logger.Warn("TemplatePath 为空,使用默认值 | TemplatePath is empty, using default"); + config.TemplatePath = @"Templates\StandardReportTemplate.json"; + } + + // 验证文件名模式 | Validate file name pattern + if (string.IsNullOrWhiteSpace(config.FileNamePattern)) + { + _logger.Warn("FileNamePattern 为空,使用默认值 | FileNamePattern is empty, using default"); + config.FileNamePattern = "{ReportId}"; + } + + // 验证页面方向 | Validate page orientation + if (config.DefaultOrientation != "Portrait" && config.DefaultOrientation != "Landscape") + { + _logger.Warn("DefaultOrientation 无效: {Value},使用默认值 Portrait | DefaultOrientation invalid: {Value}, using default Portrait", config.DefaultOrientation); + config.DefaultOrientation = "Portrait"; + } + + // 验证边距范围(0-100mm)| Validate margin range (0-100mm) + config.MarginTop = ClampMargin(config.MarginTop, "MarginTop"); + config.MarginBottom = ClampMargin(config.MarginBottom, "MarginBottom"); + config.MarginLeft = ClampMargin(config.MarginLeft, "MarginLeft"); + config.MarginRight = ClampMargin(config.MarginRight, "MarginRight"); + + // 验证 Logo 路径(如果配置了则检查文件是否存在)| Validate logo path (check file exists if configured) + if (!string.IsNullOrEmpty(config.CompanyLogo)) + { + var logoPath = Path.IsPathRooted(config.CompanyLogo) + ? config.CompanyLogo + : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, config.CompanyLogo); + + if (!File.Exists(logoPath)) + { + _logger.Warn("公司 Logo 文件不存在: {Path},将不显示 Logo | Company logo file not found: {Path}, logo will not be displayed", logoPath); + } + } + } + + /// + /// 将边距值限制在有效范围内 | Clamp margin value to valid range + /// + private float ClampMargin(float value, string name) + { + if (value < 0 || value > 100) + { + _logger.Warn("{Name} 超出有效范围 [0, 100]: {Value},使用默认值 20 | {Name} out of valid range [0, 100]: {Value}, using default 20", name, value); + return 20f; + } + return value; + } + } +} diff --git a/XP.ReportEngine/Configs/ReportConfig.cs b/XP.ReportEngine/Configs/ReportConfig.cs new file mode 100644 index 0000000..24e5365 --- /dev/null +++ b/XP.ReportEngine/Configs/ReportConfig.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace XP.ReportEngine.Configs +{ + /// + /// 报告引擎配置模型 | Report engine configuration model + /// + public class ReportConfig + { + /// + /// 报告输出文件夹路径 | Report output directory path + /// + public string OutputDirectory { get; set; } = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), + "XplorePlane", "Reports"); + + /// + /// 报告模板文件路径(相对或绝对)| Report template file path (relative or absolute) + /// + public string TemplatePath { get; set; } = @"Templates\StandardReportTemplate.json"; + + /// + /// 输出文件名模式,支持占位符 | Output file name pattern, supports placeholders + /// 支持的占位符 | Supported placeholders: + /// {ReportId} - 报告编号(如 RPT-20250512-001) + /// {CncProgram} - CNC 程序名称 + /// {ProductName} - 产品名称 + /// {ProductCode} - 产品类型码 + /// {WorkpieceSN} - 工件 SN 码 + /// {DeviceId} - 检测设备编号(本机) + /// {MachineId} - 生产机台号 + /// {Date} - 日期(yyyyMMdd) + /// {Time} - 时间(HHmmss) + /// {Result} - 综合检测结论(Pass/Fail) + /// + public string FileNamePattern { get; set; } = "{ReportId}"; + + /// + /// 文件名重复时是否自动累加序号 | Whether to auto-increment suffix when file name duplicates + /// true: 重复时生成 filename(1).pdf, filename(2).pdf ... + /// false: 直接覆盖同名文件 + /// + public bool AutoIncrementOnDuplicate { get; set; } = true; + + /// + /// 生成后是否自动打开 PDF 阅读器 | Whether to auto-open PDF viewer after generation + /// + public bool AutoOpenAfterGenerate { get; set; } = false; + + /// + /// 默认页面尺寸 | Default page size + /// + public string DefaultPageSize { get; set; } = "A4"; + + /// + /// 默认页面方向(Portrait / Landscape)| Default page orientation + /// + public string DefaultOrientation { get; set; } = "Portrait"; + + /// + /// 默认上边距(mm)| Default top margin (mm) + /// + public float MarginTop { get; set; } = 20f; + + /// + /// 默认下边距(mm)| Default bottom margin (mm) + /// + public float MarginBottom { get; set; } = 20f; + + /// + /// 默认左边距(mm)| Default left margin (mm) + /// + public float MarginLeft { get; set; } = 20f; + + /// + /// 默认右边距(mm)| Default right margin (mm) + /// + public float MarginRight { get; set; } = 20f; + + /// + /// 报告中显示的公司名称 | Company name displayed in report + /// + public string CompanyName { get; set; } = "海克斯康制造智能技术(青岛)有限公司"; + + /// + /// 公司 Logo 图片路径(可选,为空则不显示)| Company logo image path (optional, empty means no logo) + /// + public string CompanyLogo { get; set; } = string.Empty; + + /// + /// 报告中显示的软件名称 | Software name displayed in report + /// + public string SoftwareName { get; set; } = "XplorePlane"; + + /// + /// 软件 Logo 图片路径(可选,为空则不显示)| Software logo image path (optional, empty means no logo) + /// + public string SoftwareLogo { get; set; } = string.Empty; + + /// + /// 获取解析后的模板绝对路径 | Get resolved absolute template path + /// 如果 TemplatePath 是相对路径,则基于应用程序目录解析 + /// If TemplatePath is relative, resolves based on application directory + /// + public string GetResolvedTemplatePath() + { + if (Path.IsPathRooted(TemplatePath)) + { + return TemplatePath; + } + return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, TemplatePath); + } + + /// + /// 根据文件名模式和上下文参数生成实际文件名 | Generate actual file name based on pattern and context parameters + /// + /// 占位符参数字典 | Placeholder parameter dictionary + /// 生成的文件名(不含扩展名)| Generated file name (without extension) + public string ResolveFileName(Dictionary parameters) + { + var fileName = FileNamePattern; + + // 替换所有已知占位符 | Replace all known placeholders + if (parameters != null) + { + foreach (var kvp in parameters) + { + fileName = fileName.Replace($"{{{kvp.Key}}}", SanitizeFileName(kvp.Value ?? "")); + } + } + + // 替换日期和时间(始终可用)| Replace date and time (always available) + fileName = fileName.Replace("{Date}", DateTime.Now.ToString("yyyyMMdd")); + fileName = fileName.Replace("{Time}", DateTime.Now.ToString("HHmmss")); + + // 清理未被替换的占位符(替换为空)| Clean up unreplaced placeholders + fileName = System.Text.RegularExpressions.Regex.Replace(fileName, @"\{[^}]+\}", ""); + + // 移除连续的分隔符 | Remove consecutive separators + fileName = System.Text.RegularExpressions.Regex.Replace(fileName, @"[_\-]{2,}", "_"); + fileName = fileName.Trim('_', '-'); + + return string.IsNullOrWhiteSpace(fileName) ? "Report" : fileName; + } + + /// + /// 解析最终输出文件完整路径(含重复累加逻辑)| Resolve final output file full path (with duplicate increment logic) + /// + /// 占位符参数字典 | Placeholder parameter dictionary + /// 文件扩展名(含点号,如 ".pdf")| File extension (with dot, e.g. ".pdf") + /// 最终输出文件完整路径 | Final output file full path + public string ResolveOutputFilePath(Dictionary parameters, string extension = ".pdf") + { + var baseName = ResolveFileName(parameters); + var outputDir = OutputDirectory; + + // 确保输出目录存在 | Ensure output directory exists + if (!Directory.Exists(outputDir)) + { + Directory.CreateDirectory(outputDir); + } + + var filePath = Path.Combine(outputDir, baseName + extension); + + // 重复累加逻辑 | Duplicate increment logic + if (AutoIncrementOnDuplicate && File.Exists(filePath)) + { + int counter = 1; + string newPath; + do + { + newPath = Path.Combine(outputDir, $"{baseName}({counter}){extension}"); + counter++; + } while (File.Exists(newPath)); + + filePath = newPath; + } + + return filePath; + } + + /// + /// 清理文件名中的非法字符 | Sanitize illegal characters in file name + /// + private static string SanitizeFileName(string name) + { + var invalidChars = Path.GetInvalidFileNameChars(); + foreach (var c in invalidChars) + { + name = name.Replace(c, '_'); + } + return name; + } + } +} diff --git a/XP.ReportEngine/Documents/App.config.example b/XP.ReportEngine/Documents/App.config.example new file mode 100644 index 0000000..b48ec6e --- /dev/null +++ b/XP.ReportEngine/Documents/App.config.example @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XP.ReportEngine/Documents/FontFilesGuidance.md b/XP.ReportEngine/Documents/FontFilesGuidance.md new file mode 100644 index 0000000..63d4ff5 --- /dev/null +++ b/XP.ReportEngine/Documents/FontFilesGuidance.md @@ -0,0 +1,73 @@ +# 字体方案说明 | Font Strategy + +## 当前方案 | Current Approach + +XP.ReportEngine 使用 **Windows 系统自带字体** 生成 PDF,无需额外下载或嵌入字体文件。 + +| 语言 | 字体 | 文件 | 说明 | +|------|------|------|------| +| 简体中文 / 繁体中文 | 微软雅黑 | `C:\Windows\Fonts\msyh.ttc` | Windows 10+ 自带,支持简繁体 | +| 西文(英文等) | Arial | `C:\Windows\Fonts\arial.ttf` | Windows 自带 | + +## 为什么使用系统字体 | Why System Fonts + +1. **Telerik RadPdfViewer 兼容性** — 系统字体生成的 PDF 在 Telerik RadPdfViewer 中显示正常,不会出现中文乱码 +2. **无需额外部署** — 不需要随应用程序分发字体文件,减小安装包体积 +3. **跨阅读器兼容** — 字体以子集嵌入 PDF 中(`PREFER_EMBEDDED`),在任何 PDF 阅读器中都能正确显示 + +## 后备机制 | Fallback Mechanism + +`ITextPdfRenderer` 按以下顺序加载字体: + +``` +微软雅黑 (msyh.ttc) + ↓ 加载失败 +宋体 (simsun.ttc) + ↓ 加载失败 +_cjkFont = null + +Arial (arial.ttf) + ↓ 加载失败 +_westernFont = null + +最终后备: iText 内置 Helvetica(不支持中文字符) +``` + +语言选择逻辑: +- zh-CN / zh-TW → 优先使用微软雅黑 +- en-US → 优先使用 Arial,后备微软雅黑(微软雅黑也支持西文) + +## 字体子集化 | Font Subsetting + +iText7 在 `document.Close()` 时执行字体子集化: +- 分析文档中实际使用的字符 +- 从完整字体文件(微软雅黑约 15MB)中提取用到的字形子集 +- 仅嵌入子集到 PDF 中 + +这使得最终 PDF 文件大小合理(通常 200KB-2MB),但 `Close()` 操作需要约 1-1.5 秒。 + +## 性能说明 | Performance Notes + +| 阶段 | 首次耗时 | 后续耗时 | 说明 | +|------|---------|---------|------| +| 字体加载 | ~5-6s | 0ms | 首次需从磁盘读取 TTC 文件并解析 | +| 字体子集化 | ~1.2s | ~1.2s | 每次生成都需要,与字符数量相关 | + +模块通过 `WarmUpAsync()` 预热机制在应用启动时后台完成首次字体加载,用户首次生成报告时不会感受到延迟。 + +## 系统要求 | System Requirements + +- Windows 10 或更高版本(微软雅黑为系统预装字体) +- 如果在精简版 Windows 上运行,需确保系统已安装微软雅黑字体 + +## 自定义字体扩展 | Custom Font Extension + +如需添加自定义字体: + +1. 将字体文件(.ttf / .ttc / .otf)放入项目 `Fonts/` 目录 +2. 在 `.csproj` 中取消注释嵌入资源配置: + ```xml + + + ``` +3. 在 `ITextPdfRenderer.InitializeFonts()` 中扩展加载逻辑 diff --git a/XP.ReportEngine/Documents/Guidance.md b/XP.ReportEngine/Documents/Guidance.md new file mode 100644 index 0000000..6eea6f2 --- /dev/null +++ b/XP.ReportEngine/Documents/Guidance.md @@ -0,0 +1,269 @@ +# XP.ReportEngine 使用指南 | Usage Guidance + +## 1. 概述 + +本文档说明如何在 XplorePlane 项目中使用 `XP.ReportEngine` 模块生成 PDF 检测报告。 + +模块提供两种调用方式: +- **推荐**:通过 `IReportService` 门面接口(一行调用,自动处理所有细节) +- **高级**:直接使用底层管线接口(`IReportGenerator`、`IReportDataAdapter` 等) + +## 2. 前置条件 + +### 2.1 项目引用 + +在调用方项目的 `.csproj` 中添加项目引用: + +```xml + +``` + +### 2.2 模块注册 + +确保 `ReportEngineModule` 已在 `XP.App` 的模块目录中注册。模块初始化时会自动: +- 注册所有服务到 DI 容器 +- 注册多语言资源到 Fallback Chain +- 后台执行引擎预热(字体加载 + JIT 编译) + +### 2.3 配置文件 + +在 `App.config` 中添加报告引擎配置项,参见 `Documents/App.config.example`。 + +## 3. 通过 IReportService 生成报告(推荐) + +### 3.1 基本用法 + +```csharp +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +public class InspectionService +{ + private readonly IReportService _reportService; + + public InspectionService(IReportService reportService) + { + _reportService = reportService; + } + + public async Task GenerateInspectionReport( + List processorOutputs, + string productName, + string operatorName) + { + var request = new ReportRequest + { + // 必填:处理器输出数据 + ProcessorOutputs = processorOutputs, + + // 必填:报告元数据 + Metadata = new ReportMetadata + { + SampleName = productName, + OperatorName = operatorName, + InspectionDate = DateTime.Now, + Description = "BGA 焊球气泡率检测" + }, + + // 可选:文件名占位符参数(用于 FileNamePattern) + FileNameParameters = new Dictionary + { + ["ProductName"] = productName, + ["ProductCode"] = "PCBA-X100", + ["WorkpieceSN"] = "SN20250001", + ["DeviceId"] = "XP-CT-001", + ["MachineId"] = "MC01", + ["Result"] = "Pass" + } + }; + + var result = await _reportService.GenerateAsync(request); + + if (result.IsSuccess) + { + return result.OutputFilePath; // PDF 文件路径 + } + else + { + throw new Exception($"报告生成失败: {result.ErrorMessage}"); + } + } +} +``` + +### 3.2 指定输出路径 + +```csharp +var request = new ReportRequest +{ + ProcessorOutputs = outputs, + Metadata = metadata, + // 指定输出路径后,不再使用 ReportConfig 中的 OutputDirectory 和 FileNamePattern + OutputFilePath = @"D:\CustomPath\MyReport.pdf" +}; +``` + +### 3.3 注入额外图像 + +```csharp +var request = new ReportRequest +{ + ProcessorOutputs = outputs, + Metadata = metadata, + AdditionalImages = new Dictionary + { + // 工件整体图(首页显示) + ["workpieceImage"] = new ImageData + { + SourceType = ImageSourceType.FilePath, + FilePath = @"D:\Images\workpiece.png" + }, + // 自定义图像 + ["customImage"] = new ImageData + { + SourceType = ImageSourceType.Bytes, + Bytes = imageBytes + } + } +}; +``` + +### 3.4 注入自定义属性 + +```csharp +var request = new ReportRequest +{ + ProcessorOutputs = outputs, + Metadata = metadata, + // 自定义属性会合并到 ReportContext.Properties,可在模板中通过 ${key} 绑定 + CustomProperties = new Dictionary + { + ["batchNumber"] = "BATCH-2025-001", + ["inspectionStation"] = "Station-A" + } +}; +``` + +## 4. ReportRequest 完整字段说明 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `ProcessorOutputs` | `List` | 是 | 处理器输出数据列表 | +| `Metadata` | `ReportMetadata` | 是 | 报告元数据 | +| `OutputFilePath` | `string` | 否 | 输出路径,为空时自动生成 | +| `FileNameParameters` | `Dictionary` | 否 | 文件名占位符参数 | +| `AdditionalImages` | `Dictionary` | 否 | 额外图像数据 | +| `CustomProperties` | `Dictionary` | 否 | 自定义属性 | + +### ReportMetadata 字段 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `ReportId` | `string` | 报告编号(为空时自动生成 RPT-yyyyMMdd-NNN) | +| `InspectionDate` | `DateTime` | 检测日期 | +| `SampleName` | `string` | 样品/产品名称 | +| `OperatorName` | `string` | 操作员 | +| `Description` | `string` | 描述信息 | + +### ProcessorOutput 字段 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `ProcessorType` | `string` | 处理器类型标识 | +| `OutputData` | `Dictionary` | 输出数据字典 | +| `AnnotatedImage` | `ImageData` | 关联的已标注图像 | + +支持的 ProcessorType: +- `LineMeasurementProcessor` — 线测量 +- `BgaVoidRateProcessor` — BGA 气泡率 +- `VoidMeasurementProcessor` — 空隙测量 +- `FillRateProcessor` — 通孔填锡率 + +## 5. ReportServiceResult 结果说明 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `IsSuccess` | `bool` | 是否成功 | +| `OutputFilePath` | `string` | 输出文件路径(成功时有值) | +| `ReportId` | `string` | 报告编号 | +| `ErrorMessage` | `string` | 错误信息(失败时有值) | +| `Exception` | `Exception` | 异常对象(失败时有值) | + +## 6. 在 ViewModel 中使用(带 UI 交互) + +如果需要进度条、文件对话框等 UI 交互,参考 `ReportDemoViewModel.cs` 的实现模式: + +```csharp +// 在后台线程执行,避免阻塞 UI +var genResult = await Task.Run(() => _reportService.GenerateAsync(request)); +``` + +关键点: +- `IReportService.GenerateAsync` 内部是 CPU 密集型操作(PDF 渲染) +- 必须用 `Task.Run` 推到线程池,否则会阻塞 UI 线程 +- 进度条、对话框等 UI 逻辑留在 ViewModel 中 + +## 7. 高级用法:直接使用底层管线 + +适用于需要自定义管线某个阶段的场景: + +```csharp +// 1. 数据适配 +var adapter = container.Resolve(); +var context = adapter.Adapt(processorOutputs, metadata); + +// 2. 手动修改上下文 +context.Properties["customKey"] = "customValue"; +context.Images["myImage"] = new ImageData { ... }; + +// 3. 调用管线生成 +var generator = container.Resolve(); +var options = new ReportGenerationOptions +{ + TemplatePath = "Templates/StandardReportTemplate.json", + OutputFilePath = @"D:\output.pdf", + Format = ReportOutputFormat.Pdf +}; + +var result = await generator.GenerateAsync(context, options); +``` + +## 8. 预热机制 + +模块启动时自动在后台执行预热,无需手动调用。如果需要在特定时机手动预热: + +```csharp +var reportService = container.Resolve(); +await reportService.WarmUpAsync(); +``` + +预热内容: +- iText7 程序集加载 +- BouncyCastle 加密提供程序注册 +- 微软雅黑字体文件读取和解析(约 5-6 秒) +- JSON 模板反序列化 JIT 编译 +- 管线各阶段代码 JIT 编译 + +预热完成后,首次正式生成报告不会有额外延迟。 + +## 9. 线程安全 + +`IReportService` 内部使用 `SemaphoreSlim(1, 1)` 互斥锁,确保: +- 预热与正式生成不会并发执行 +- 多个并发的 `GenerateAsync` 调用会串行执行 + +这是因为 `ITextPdfRenderer` 的字体字段在每次渲染时重置,并发渲染会导致 iText7 的 `"belongs to other PDF document"` 错误。 + +## 10. 常见问题 + +### Q: 首次生成报告很慢? +A: 正常现象。首次需要加载字体(~5s)+ 字体子集化(~1.2s)。预热机制会在应用启动时后台完成字体加载,用户首次操作时只需等待子集化时间。 + +### Q: PDF 中图像显示为"无图像"占位矩形? +A: 检查 `ProcessorOutput.AnnotatedImage` 或 `ReportRequest.AdditionalImages` 中的图像路径是否正确、文件是否存在。 + +### Q: 报告中某些字段为空? +A: 检查 `ProcessorOutput.OutputData` 中的键名是否与 `ProcessorDataAdapter` 中的映射一致(区分大小写)。 + +### Q: 如何自定义报告模板? +A: 修改 `Templates/StandardReportTemplate.json`,参考 `Documents/XP.ReportEngineModelDefine.md` 中的模板结构定义。 diff --git a/XP.ReportEngine/Documents/README.md b/XP.ReportEngine/Documents/README.md new file mode 100644 index 0000000..a53dc39 --- /dev/null +++ b/XP.ReportEngine/Documents/README.md @@ -0,0 +1,217 @@ +# XP.ReportEngine — PDF 报告生成引擎 + +## 概述 + +XP.ReportEngine 是 XplorePlane 平面 CT 检测系统的 PDF 报告生成模块。负责将检测分析结果(距离测量、BGA 气泡率、空隙测量、通孔填锡率)转换为结构化的 PDF 检测报告。 + +模块采用管线式架构(Pipeline),将报告生成过程分解为五个独立阶段: +**模板加载 → 数据适配 → 数据绑定 → 排版计算 → PDF 渲染** + +对外提供 `IReportService` 门面接口,外部模块只需构建 `ReportRequest` 即可一行调用完成报告生成。 + +## 技术栈 + +| 依赖 | 版本 | 用途 | +|------|------|------| +| .NET 8.0 | net8.0-windows7.0 | 运行时 | +| iText7 | 8.0.5 | PDF 文档生成核心库 | +| itext7.bouncy-castle-adapter | 8.0.5 | iText7 加密支持 | +| Newtonsoft.Json | 13.0.3 | JSON 模板反序列化 | +| Prism.Wpf | 9.0.537 | 模块化框架与 DI | +| Telerik UI for WPF | 2024.1.408 | UI 控件(演示窗口) | +| XP.Common | — | 日志、本地化、通用窗体、PDF 阅读器 | + +## 项目结构 + +``` +XP.ReportEngine/ +├── Configs/ # 配置加载 +│ ├── ConfigLoader.cs +│ └── ReportConfig.cs +├── Interfaces/ # 核心接口定义 +│ ├── IReportService.cs ★ 门面接口(外部调用入口) +│ ├── IReportGenerator.cs +│ ├── IReportGeneratorFactory.cs +│ ├── ITemplateEngine.cs +│ ├── IDataBinder.cs +│ ├── ILayoutEngine.cs +│ ├── IPdfRenderer.cs +│ └── IReportDataAdapter.cs +├── Models/ # 数据模型 +│ ├── ReportRequest.cs ★ 报告生成请求 +│ ├── ReportServiceResult.cs ★ 报告服务结果 +│ ├── ReportContext.cs +│ ├── ReportMetadata.cs +│ ├── ImageData.cs +│ ├── ReportTemplate.cs +│ ├── TemplateElement.cs +│ ├── LayoutPage.cs +│ ├── ReportResult.cs +│ ├── ReportGenerationOptions.cs +│ ├── ProcessorOutput.cs +│ └── TemplateValidationResult.cs +├── Services/ # 服务实现 +│ ├── ReportService.cs ★ 门面服务实现 +│ ├── PdfReportGenerator.cs # 管线协调器 +│ ├── ReportGeneratorFactory.cs # 工厂 +│ ├── JsonTemplateEngine.cs # JSON 模板加载与验证 +│ ├── ExpressionDataBinder.cs # ${} 表达式数据绑定 +│ ├── PageLayoutEngine.cs # 分页与排版 +│ ├── ITextPdfRenderer.cs # iText7 PDF 渲染 +│ ├── ProcessorDataAdapter.cs # 处理器数据适配 +│ └── ReportIdGenerator.cs # 报告编号生成(RPT-yyyyMMdd-NNN) +├── Templates/ # JSON 报告模板 +│ └── StandardReportTemplate.json +├── Resources/ # 多语言资源文件 +│ ├── Resources.resx +│ ├── Resources.zh-CN.resx +│ ├── Resources.zh-TW.resx +│ └── Resources.en-US.resx +├── ViewModels/ # 演示窗口 ViewModel +│ └── ReportDemoViewModel.cs +├── Views/ # 演示窗口 View +│ ├── ReportDemoWindow.xaml +│ └── ReportDemoWindow.xaml.cs +├── Documents/ # 项目文档 +│ ├── README.md ← 本文件 +│ ├── Guidance.md # 使用指南 +│ ├── App.config.example # 配置示例 +│ ├── FontFilesGuidance.md # 字体方案说明 +│ ├── XP.ReportEngineDesign.md # 架构设计文档 +│ └── XP.ReportEngineModelDefine.md # 模型定义文档 +├── ReportEngineModule.cs # Prism 模块入口 +└── XP.ReportEngine.csproj +``` + +## 核心接口 + +| 接口 | 实现类 | 职责 | +|------|--------|------| +| **`IReportService`** | **`ReportService`** | **门面接口,外部模块调用入口** | +| `IReportGenerator` | `PdfReportGenerator` | 协调管线各阶段,生成 PDF | +| `IReportGeneratorFactory` | `ReportGeneratorFactory` | 根据格式创建对应生成器 | +| `ITemplateEngine` | `JsonTemplateEngine` | JSON 模板加载、反序列化、验证 | +| `IDataBinder` | `ExpressionDataBinder` | `${}` 表达式解析与数据绑定 | +| `ILayoutEngine` | `PageLayoutEngine` | 分页、元素定位、表格跨页 | +| `IPdfRenderer` | `ITextPdfRenderer` | 使用 iText7 渲染 PDF | +| `IReportDataAdapter` | `ProcessorDataAdapter` | ProcessorOutput → ReportContext 转换 | + +## 架构分层 + +``` +┌─────────────────────────────────────────────────────┐ +│ 外部调用方(XP.App、其他模块) │ +│ 注入 IReportService,传入 ReportRequest │ +└──────────────────────┬──────────────────────────────┘ + │ +┌──────────────────────▼──────────────────────────────┐ +│ ReportService(门面层) │ +│ 生成报告ID → 解析输出路径 → 数据适配 → 注入配置数据 │ +└──────────────────────┬──────────────────────────────┘ + │ +┌──────────────────────▼──────────────────────────────┐ +│ PdfReportGenerator(管线协调层) │ +│ 模板加载 → 数据绑定 → 排版计算 → PDF 渲染 → 保存 │ +└─────────────────────────────────────────────────────┘ +``` + +## 快速开始 + +详细使用指南请参阅 `Documents/Guidance.md`。 + +### 最简调用(通过 IReportService) + +```csharp +public class MyService +{ + private readonly IReportService _reportService; + + public MyService(IReportService reportService) + { + _reportService = reportService; + } + + public async Task GenerateReport(List outputs) + { + var request = new ReportRequest + { + ProcessorOutputs = outputs, + Metadata = new ReportMetadata + { + SampleName = "PCB-001", + OperatorName = "张三", + InspectionDate = DateTime.Now + } + }; + + var result = await _reportService.GenerateAsync(request); + + if (result.IsSuccess) + { + // result.OutputFilePath — 生成的 PDF 路径 + // result.ReportId — 报告编号 + } + } +} +``` + +## 预热机制 + +模块在 Prism 初始化时自动在后台执行一次预热(`WarmUpAsync`),触发 iText7 初始化、字体加载、JIT 编译等一次性开销,避免用户首次生成报告时卡顿。 + +预热与正式生成通过 `SemaphoreSlim` 互斥锁串行执行,不会出现并发冲突。 + +## 数据绑定表达式 + +模板中支持以下绑定语法: + +| 语法 | 说明 | 示例 | +|------|------|------| +| `${propertyName}` | 简单属性绑定 | `${sampleName}` | +| `${object.property}` | 嵌套属性路径 | `${metadata.reportId}` | +| `${list[index]}` | 列表索引访问 | `${bgaBalls[0].voidRate}` | +| `${functionName(param)}` | 格式化函数 | `${formatDate(inspectionDate)}` | +| `${loc:ResourceKey}` | 本地化键解析 | `${loc:Report_Title}` | + +## 多语言支持 + +支持三种语言:简体中文(zh-CN)、繁体中文(zh-TW)、英文(en-US)。 + +通过 `ILocalizationService` 自动解析 `${loc:Key}` 表达式为当前语言文本。模块在初始化时注册资源源到 Fallback Chain。 + +## 模板页面类型 + +标准模板 `StandardReportTemplate.json` 包含以下页面类型: + +| 页面类型 | 说明 | +|---------|------| +| `homepage` | 报告首页(公司信息 + 元数据 + 汇总表格) | +| `summary` | 检测结果汇总页 | +| `metricData` | 距离测量数据页 | +| `bgaInspection` | BGA 焊球检测页(含数据表格) | +| `voidInspection` | 空隙检测页(含数据表格) | +| `viaFillInspection` | 通孔填锡检测页 | + +## 错误处理 + +模块采用结果对象模式(Result Pattern): +- `ReportServiceResult.Success(path, reportId)` — 成功 +- `ReportServiceResult.Failure(message, ex)` — 失败 + +非致命性问题(缺失属性、图像缺失)会记录警告日志并继续执行,不会中断报告生成。 + +## 构建 + +```bash +cd XplorePlane +dotnet build XP.ReportEngine/XP.ReportEngine.csproj +``` + +## 相关文档 + +- `Documents/Guidance.md` — 详细使用指南(IReportService 调用方式) +- `Documents/TemplateDevelopment.md` — 模板开发指南(新增/自定义模板) +- `Documents/App.config.example` — 配置文件示例 +- `Documents/FontFilesGuidance.md` — 字体方案说明 +- `Documents/XP.ReportEngineDesign.md` — 架构设计文档 +- `Documents/XP.ReportEngineModelDefine.md` — 模型定义文档 diff --git a/XP.ReportEngine/Documents/TemplateDevelopment.md b/XP.ReportEngine/Documents/TemplateDevelopment.md new file mode 100644 index 0000000..cdc3b6d --- /dev/null +++ b/XP.ReportEngine/Documents/TemplateDevelopment.md @@ -0,0 +1,403 @@ +# 报告模板开发指南 | Template Development Guide + +## 1. 概述 + +XP.ReportEngine 使用 JSON 格式定义报告模板。模板描述了 PDF 报告的页面结构、元素布局、数据绑定和样式定义。 + +模板文件存放在 `XP.ReportEngine/Templates/` 目录下,通过 `App.config` 中的 `Report:TemplatePath` 配置项指定使用哪个模板。 + +## 2. 新增模板步骤 + +### 2.1 创建模板文件 + +1. 在 `Templates/` 目录下创建新的 JSON 文件,如 `CustomReportTemplate.json` +2. 在 `.csproj` 中确认模板文件会被复制到输出目录(已有通配规则): + ```xml + + PreserveNewest + + ``` +3. 修改 `App.config` 中的 `Report:TemplatePath` 指向新模板: + ```xml + + ``` + +### 2.2 模板验证规则 + +模板加载后会自动验证,必须满足以下条件: +- 包含 `document` 顶层字段(页面设置) +- 包含 `pages` 顶层字段(至少一个页面定义) +- 包含 `styles` 顶层字段(样式字典) + +验证失败时报告生成会返回错误,不会生成 PDF。 + +## 3. 模板 JSON 结构 + +```json +{ + "document": { ... }, // 必需:文档级设置(页面尺寸、边距、页眉页脚) + "pages": [ ... ], // 必需:页面定义数组 + "styles": { ... } // 必需:样式定义字典 +} +``` + +## 4. document 配置 + +```json +{ + "document": { + "pageSize": "A4", + "orientation": "Portrait", + "margins": { "top": 40, "bottom": 20, "left": 20, "right": 20 }, + "header": { + "enabled": true, + "left": ["标题文本", "第二行文本"], + "right": ["右侧文本"], + "rightImageKey": "companyLogo", + "leftImageKey": "softwareLogo", + "fontSize": 7, + "color": "#666666", + "showLine": true + }, + "footer": { + "enabled": true, + "left": ["公司名称"], + "right": ["{currentPage} / {totalPages}"], + "fontSize": 8, + "color": "#666666", + "showLine": true + } + } +} +``` + +| 字段 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `pageSize` | string | `"A4"` | 页面尺寸 | +| `orientation` | string | `"Portrait"` | 方向:Portrait / Landscape | +| `margins` | object | `{top:20, bottom:20, left:20, right:20}` | 边距(mm) | +| `header` | object | null | 页眉配置(首页不显示) | +| `footer` | object | null | 页脚配置(首页不显示) | + +### 页眉/页脚字段 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `enabled` | bool | 是否启用 | +| `left` | string[] | 左侧文本行(支持 `${}` 绑定) | +| `right` | string[] | 右侧文本行(支持 `${}` 绑定) | +| `leftImageKey` | string | 左侧图像的 dataKey | +| `rightImageKey` | string | 右侧图像的 dataKey | +| `fontSize` | float | 字体大小 | +| `color` | string | 字体颜色(十六进制) | +| `showLine` | bool | 是否显示分隔线 | + +页脚特殊占位符: +- `{currentPage}` — 当前页码 +- `{totalPages}` — 总页数 + +## 5. pages 页面定义 + +```json +{ + "pages": [ + { + "type": "homepage", + "elements": [ ... ] + }, + { + "type": "customPage", + "elements": [ ... ] + } + ] +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `type` | string | 页面类型标识(`homepage` 类型不显示页眉页脚) | +| `elements` | array | 页面内的元素列表 | + +### 内置页面类型 + +| 类型 | 说明 | 特殊行为 | +|------|------|---------| +| `homepage` | 首页 | 不显示页眉页脚 | +| `summary` | 汇总页 | 无 | +| `metricData` | 距离测量页 | 无 | +| `bgaInspection` | BGA 检测页 | 无 | +| `voidInspection` | 空隙检测页 | 无 | +| `viaFillInspection` | 通孔填锡页 | 无 | + +你可以自定义任意 `type` 名称,只有 `homepage` 有特殊行为(不显示页眉页脚)。 + +## 6. 元素类型 + +### 6.1 text — 文本元素 + +```json +{ + "type": "text", + "content": "${loc:Report_Title}", + "style": "heading", + "positioning": "flow", + "align": "center", + "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `content` | string | 文本内容,支持 `${}` 绑定表达式 | +| `style` | string | 引用 `styles` 中定义的样式名 | +| `align` | string | 对齐:left / center / right | +| `colorRules` | object | 条件颜色规则(内容包含关键词时变色) | + +### 6.2 image — 图像元素 + +```json +{ + "type": "image", + "dataKey": "workpieceImage", + "size": [160, 110], + "border": true, + "align": "center", + "style": "imageDefault", + "positioning": "flow" +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `dataKey` | string | 图像数据键(对应 `ReportContext.Images` 中的键) | +| `size` | float[2] | [宽, 高](mm),图像会等比缩放适应 | +| `border` | bool | 是否显示边框 | +| `align` | string | 对齐:left / center / right | + +图像缺失时会渲染灰色占位矩形,不会中断报告生成。 + +### 6.3 table — 表格元素 + +```json +{ + "type": "table", + "dataKey": "bgaBallsTable", + "positioning": "flow", + "size": [170, 0], + "style": "tableDefault", + "columns": [ + { "header": "序号", "field": "index", "width": 25, "align": "center" }, + { "header": "气泡率", "field": "voidRate", "width": 40, "align": "center" }, + { "header": "面积", "field": "area", "width": 40, "align": "center" }, + { + "header": "分类", + "field": "classification", + "width": 35, + "align": "center", + "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } + } + ] +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `dataKey` | string | 表格数据键(对应 `ReportContext.Properties` 中的 `List>` 数据) | +| `size` | float[2] | [宽, 高](mm),高度为 0 表示自动 | +| `columns` | array | 列定义数组 | + +#### 列定义(ColumnDefinition) + +| 字段 | 类型 | 说明 | +|------|------|------| +| `header` | string | 表头文本(支持 `${}` 绑定) | +| `field` | string | 数据字段名(对应行数据字典中的键) | +| `width` | float | 列宽(mm) | +| `align` | string | 对齐:left / center / right | +| `colorRules` | object | 条件颜色规则(单元格值匹配时变色) | + +### 6.4 row — 水平布局容器 + +```json +{ + "type": "row", + "size": [170, 100], + "widths": [6, 4], + "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "myImage", "size": [110, 90] } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "文本内容", "style": "body" } + ] + } + ] +} +``` + +| 字段 | 类型 | 说明 | +|------|------|------| +| `size` | float[2] | [总宽, 总高](mm) | +| `widths` | float[] | 列宽比例数组(如 `[6, 4]` 表示 60%:40%) | +| `children` | array | 子列元素(`type: "column"`) | + +### 6.5 spacer — 间距元素 + +```json +{ "type": "spacer", "size": [170, 10], "positioning": "flow" } +``` + +用于在元素之间添加垂直间距。`size[1]` 为间距高度(mm)。 + +### 6.6 divider — 分隔线 + +```json +{ "type": "divider", "positioning": "flow" } +``` + +渲染一条水平分隔线。 + +### 6.7 pagebreak — 强制分页 + +```json +{ "type": "pagebreak" } +``` + +在当前位置强制插入分页符。 + +## 7. 样式定义 + +```json +{ + "styles": { + "heading": { + "font": "auto", + "size": 16, + "bold": true, + "italic": false, + "color": "#333333", + "align": "left", + "marginTop": 0, + "marginBottom": 3, + "paddingLeft": 0, + "lineHeight": 0, + "backgroundColor": "" + } + } +} +``` + +| 字段 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `font` | string | `"auto"` | 字体(`auto` 根据语言自动选择) | +| `size` | float | 12 | 字体大小(pt) | +| `bold` | bool | false | 粗体 | +| `italic` | bool | false | 斜体 | +| `color` | string | `"#000000"` | 字体颜色(十六进制) | +| `align` | string | `"left"` | 对齐:left / center / right | +| `backgroundColor` | string | — | 背景色(十六进制) | +| `marginTop` | float | 0 | 上边距(mm) | +| `marginBottom` | float | 0 | 下边距(mm) | +| `paddingLeft` | float | 0 | 左缩进(mm) | +| `lineHeight` | float | 0 | 行高倍数(0 = 默认) | + +元素引用未定义的样式名时,会使用默认样式(12pt、黑色、左对齐),不会报错。 + +## 8. 数据绑定表达式 + +模板中的 `content`、`header` 等文本字段支持 `${}` 绑定表达式: + +| 语法 | 说明 | 示例 | +|------|------|------| +| `${key}` | 从 Properties 中取值 | `${sampleName}` | +| `${metadata.field}` | 从 Metadata 中取值 | `${metadata.reportId}` | +| `${loc:Key}` | 多语言资源键 | `${loc:Report_Title}` | +| `${formatDate(value)}` | 格式化日期 | `${formatDate(metadata.inspectionDate)}` | +| `${formatNumber(value, decimals)}` | 格式化数字 | `${formatNumber(totalArea, 2)}` | +| `${formatPercent(value)}` | 格式化百分比 | `${formatPercent(voidRate)}` | + +### 数据来源 + +绑定表达式从 `ReportContext` 中查找数据: +- `Properties` 字典 — 扁平化的键值对(由 `ProcessorDataAdapter` 从处理器输出转换而来) +- `Metadata` — 报告元数据对象 +- `Images` 字典 — 图像数据(通过 `dataKey` 引用) + +### ProcessorDataAdapter 输出的键名 + +| 处理器类型 | Properties 中的键 | Images 中的键 | 表格 dataKey | +|-----------|------------------|--------------|-------------| +| LineMeasurementProcessor | measurementType, point1, point2, pixelDistance, actualDistance, unit, angle | lineMeasurementImage | — | +| BgaVoidRateProcessor | bgaCount, voidRate, fillRate, totalBgaArea, totalVoidArea, voidLimit, classification | bgaInspectionImage | bgaBallsTable | +| VoidMeasurementProcessor | roiArea, totalVoidArea, voidRate, voidLimit, voidCount, maxVoidArea, classification | voidInspectionImage | voidsTable | +| FillRateProcessor | fillRate, voidRate, fullDistance, fillDistance, thtLimit, classification, e1-e4 | viaFillImage | — | + +### ReportService 自动注入的键 + +| 键 | 来源 | 说明 | +|----|------|------| +| `CompanyName` | ReportConfig | 公司名称 | +| `SoftwareName` | ReportConfig | 软件名称 | +| `companyLogo` | ReportConfig.CompanyLogo | 公司 Logo(Images) | +| `softwareLogo` | ReportConfig.SoftwareLogo | 软件 Logo(Images) | +| `summaryTable` | 自动生成 | 首页汇总表数据 | + +## 9. 定位方式 + +| 值 | 说明 | +|----|------| +| `"flow"` | 流式布局,元素按顺序从上到下排列(推荐) | +| `"absolute"` | 绝对定位,使用 `position` 坐标(不推荐,兼容性差) | + +建议所有元素使用 `"positioning": "flow"`。 + +## 10. 完整模板示例(最小化) + +```json +{ + "document": { + "pageSize": "A4", + "orientation": "Portrait", + "margins": { "top": 20, "bottom": 20, "left": 20, "right": 20 } + }, + "pages": [ + { + "type": "homepage", + "elements": [ + { "type": "text", "content": "检测报告", "style": "title", "positioning": "flow" }, + { "type": "text", "content": "报告编号:${metadata.reportId}", "style": "body", "positioning": "flow" }, + { "type": "text", "content": "检测日期:${formatDate(metadata.inspectionDate)}", "style": "body", "positioning": "flow" } + ] + }, + { + "type": "dataPage", + "elements": [ + { "type": "text", "content": "检测数据", "style": "heading", "positioning": "flow" }, + { "type": "image", "dataKey": "inspectionImage", "size": [150, 100], "positioning": "flow" } + ] + } + ], + "styles": { + "title": { "size": 24, "bold": true, "align": "center" }, + "heading": { "size": 16, "bold": true }, + "body": { "size": 12 } + } +} +``` + +## 11. 注意事项 + +1. **尺寸单位**:所有尺寸(size、margins、width)单位为 **mm**(毫米) +2. **颜色格式**:使用十六进制格式 `#RRGGBB`(如 `#FF0000` 为红色) +3. **表格自动跨页**:当表格数据行超出当前页面剩余空间时,排版引擎会自动分页 +4. **图像缺失容错**:图像 dataKey 对应的数据不存在时,渲染占位矩形,不中断生成 +5. **样式缺失容错**:引用未定义的样式名时使用默认样式,不中断生成 +6. **绑定表达式缺失**:`${}` 表达式对应的数据不存在时,替换为空字符串 +7. **首页特殊处理**:`type: "homepage"` 的页面不显示页眉页脚 +8. **JSON 编码**:模板文件必须使用 **UTF-8** 编码保存 diff --git a/XP.ReportEngine/Documents/XP.ReportEngineDesign.md b/XP.ReportEngine/Documents/XP.ReportEngineDesign.md new file mode 100644 index 0000000..490c1a8 --- /dev/null +++ b/XP.ReportEngine/Documents/XP.ReportEngineDesign.md @@ -0,0 +1,422 @@ +# XP.ReportEngine 项目规划 + +## 一、项目结构优化 + +**1. 完整目录结构** + +``` +XP.ReportEngine/ +├── Interfaces/ +│ ├── IReportGenerator.cs // 报告生成器核心接口 +│ ├── ITemplateEngine.cs // 模板引擎接口 +│ └── IDataBinder.cs // 数据绑定接口 +├── Models/ +│ ├── ReportContext.cs // 报告上下文(包含测量数据、图片列表) +│ ├── ReportTemplate.cs // 报告模板定义 +│ ├── TemplateElement.cs // 模板元素定义 +│ └── LayoutSettings.cs // 布局配置参数 +├── Services/ +│ ├── MeasurementReportBuilder.cs // 测量报告构建器 +│ ├── ImageLayoutService.cs // 图片排版服务(计算坐标、缩放) +│ ├── TemplateEngine.cs // 模板引擎实现 +│ ├── DataBinder.cs // 数据绑定实现 +│ └── PdfGenerationService.cs // PDF生成核心服务 +├── Templates/ +│ └── StandardReportTemplate.json // 标准报告模板配置 +└── Extensions/ + └── ImageExtensions.cs // 图像处理扩展方法 +``` + +## 二、核心模块设计 + +### 1. 报告模板引擎 + +**1.1 模板定义规范** + +- **JSON模板结构**: + + ```json + { + "document": { + "pageSize": "A4", + "margins": { "top": 20, "bottom": 20, "left": 20, "right": 20 } + }, + "pages": [ + { + "type": "title", + "elements": [ + { "type": "text", "content": "工业CT检测报告", "style": "title", "position": [10, 10] }, + { "type": "text", "content": "报告日期: ${reportDate}", "style": "subtitle", "position": [10, 30] } + ] + }, + { + "type": "measurement", + "elements": [ + { "type": "table", "dataKey": "measurements", "position": [10, 10], "size": [190, 100] }, + { "type": "image", "dataKey": "overviewImage", "position": [10, 120], "size": [190, 100] } + ] + }, + { + "type": "defectDetail", + "elements": [ + { "type": "image", "dataKey": "defectImage", "position": [10, 10], "size": [90, 90] }, + { "type": "text", "content": "缺陷类型: ${defectType}", "style": "normal", "position": [10, 100] } + ] + } + ], + "styles": { + "title": { "font": "Arial", "size": 24, "bold": true, "color": "#000000" }, + "subtitle": { "font": "Arial", "size": 16, "italic": true, "color": "#666666" }, + "normal": { "font": "Arial", "size": 12, "color": "#000000" } + } + } + ``` + +**1.2 模板引擎实现** + +- **模板加载与解析**: + + ```csharp + public class TemplateEngine : ITemplateEngine + { + public ReportTemplate LoadTemplate(string templatePath) + { + var json = File.ReadAllText(templatePath); + return JsonConvert.DeserializeObject(json); + } + + public List ParseTemplate(ReportTemplate template, ReportContext context) + { + var elements = new List(); + + foreach (var page in template.Pages) + { + foreach (var element in page.Elements) + { + // 处理数据绑定 + var boundElement = BindData(element, context); + elements.Add(boundElement); + } + } + + return elements; + } + + private PageElement BindData(PageElement element, ReportContext context) + { + // 实现数据绑定逻辑 + if (element.Type == "text" && element.Content.Contains("${")) + { + element.Content = DataBinder.Bind(element.Content, context); + } + return element; + } + } + ``` + +### 2. 数据绑定系统 + +**2.1 数据绑定机制** + +- **支持的绑定语法**: + - `${propertyName}` - 基本属性绑定 + - `${object.property}` - 对象属性绑定 + - `${list[index]}` - 列表索引访问 + - `${function(param)}` - 函数调用(如日期格式化) + +**2.2 数据绑定实现** + +```csharp +public class DataBinder : IDataBinder +{ + public string Bind(string template, ReportContext context) + { + // 使用正则表达式匹配绑定表达式 + var pattern = @"\$\{([^\}]+)\}"; + return Regex.Replace(template, pattern, match => + { + var expression = match.Groups[1].Value; + return EvaluateExpression(expression, context); + }); + } + + private string EvaluateExpression(string expression, ReportContext context) + { + // 解析表达式并获取值 + if (expression.Contains(".")) + { + // 处理对象属性 + var parts = expression.Split('.'); + var obj = context.GetType().GetProperty(parts[0])?.GetValue(context); + return obj?.GetType().GetProperty(parts[1])?.GetValue(obj)?.ToString() ?? string.Empty; + } + else if (expression.Contains("[")) + { + // 处理列表索引 + var index = int.Parse(expression.Split('[')[1].TrimEnd(']')); + return context.Images.Count > index ? "Image" : string.Empty; + } + else + { + // 处理基本属性 + return context.GetType().GetProperty(expression)?.GetValue(context)?.ToString() ?? string.Empty; + } + } +} +``` + +### 3. 自动排版功能 + +**3.1 布局引擎设计** + +- **核心功能**: + - **页面分隔**: 当内容超出一页时自动创建新页 + - **元素定位**: 根据模板定义计算元素在页面上的精确位置 + - **尺寸计算**: 自动调整元素大小以适应内容 + - **响应式布局**: 根据页面尺寸动态调整元素位置 + +**3.2 排版服务实现** + +```csharp +public class ImageLayoutService +{ + public LayoutResult CalculateLayout(ReportTemplate template, ReportContext context) + { + var result = new LayoutResult(); + var currentPage = 0; + var currentY = template.Document.Margins.Top; + + foreach (var page in template.Pages) + { + foreach (var element in page.Elements) + { + // 计算元素位置 + var position = new Point( + template.Document.Margins.Left + element.Position[0], + currentY + element.Position[1] + ); + + // 计算元素尺寸 + var size = new Size(element.Size[0], element.Size[1]); + + // 检查是否需要换页 + if (position.Y + size.Height > PageSize.A4.Height - template.Document.Margins.Bottom) + { + currentPage++; + currentY = template.Document.Margins.Top; + position = new Point( + template.Document.Margins.Left + element.Position[0], + currentY + element.Position[1] + ); + } + + // 添加到布局结果 + result.Elements.Add(new LayoutElement + { + Page = currentPage, + Element = element, + Position = position, + Size = size + }); + + // 更新当前Y位置 + currentY = position.Y + size.Height; + } + } + + return result; + } +} +``` + +### 4. 图表嵌入实现 + +**4.1 WPF图表转PDF图像** + +- **实现方案**: + - 使用`RenderTargetBitmap`将WPF控件渲染为位图 + - 支持高质量图像输出(300 DPI) + - 提供图像压缩选项,平衡质量与文件大小 + +**4.2 图像转换服务** + +```csharp +public static class ImageExtensions +{ + public static byte[] ToPdfImage(this ImageSource image, double width, double height) + { + var renderTarget = new RenderTargetBitmap( + (int)width, (int)height, + 96, 96, PixelFormats.Pbgra32); + + renderTarget.Render(image); + + using (var stream = new MemoryStream()) + { + var encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(renderTarget)); + encoder.Save(stream); + return stream.ToArray(); + } + } + + public static byte[] ToPdfImage(this FrameworkElement element, double width, double height) + { + var renderTarget = new RenderTargetBitmap( + (int)width, (int)height, + 96, 96, PixelFormats.Pbgra32); + + renderTarget.Render(element); + + using (var stream = new MemoryStream()) + { + var encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(renderTarget)); + encoder.Save(stream); + return stream.ToArray(); + } + } +} +``` + +## 三、PDF生成核心流程 + +### 1. 生成步骤 + +1. **加载模板**: 从Templates目录加载JSON模板 +2. **解析上下文**: 将MeasurementData和图片列表转换为ReportContext +3. **数据绑定**: 将上下文数据绑定到模板中的占位符 +4. **计算布局**: 确定每个元素在PDF页面上的精确位置 +5. **生成PDF**: 使用iTextSharp绘制内容到PDF文档 +6. **输出结果**: 返回MemoryStream或保存为文件 + +### 2. 核心生成服务 + +```csharp +public class PdfGenerationService +{ + public MemoryStream GeneratePdf(ReportContext context, string templatePath) + { + // 1. 加载模板 + var templateEngine = new TemplateEngine(); + var template = templateEngine.LoadTemplate(templatePath); + + // 2. 解析模板元素 + var elements = templateEngine.ParseTemplate(template, context); + + // 3. 计算布局 + var layoutService = new ImageLayoutService(); + var layout = layoutService.CalculateLayout(template, context); + + // 4. 创建PDF文档 + var document = new Document(PageSize.A4, + template.Document.Margins.Left, + template.Document.Margins.Right, + template.Document.Margins.Top, + template.Document.Margins.Bottom); + + var stream = new MemoryStream(); + var writer = PdfWriter.GetInstance(document, stream); + document.Open(); + + // 5. 绘制内容 + DrawContent(document, layout, context); + + // 6. 关闭文档 + document.Close(); + + return stream; + } + + private void DrawContent(Document document, LayoutResult layout, ReportContext context) + { + // 实现内容绘制逻辑 + foreach (var element in layout.Elements) + { + switch (element.Element.Type) + { + case "text": + DrawText(document, element); + break; + case "image": + DrawImage(document, element, context); + break; + case "table": + DrawTable(document, element, context); + break; + } + } + } + + private void DrawText(Document document, LayoutElement element) + { + var paragraph = new Paragraph(element.Element.Content); + paragraph.SetLocation(element.Position.X, document.PageSize.Height - element.Position.Y); + document.Add(paragraph); + } + + private void DrawImage(Document document, LayoutElement element, ReportContext context) + { + // 获取图像数据 + var imageData = context.Images.FirstOrDefault(); + if (imageData == null) return; + + // 创建iTextSharp图像对象 + var image = Image.GetInstance(imageData); + image.SetAbsolutePosition(element.Position.X, document.PageSize.Height - element.Position.Y - element.Size.Height); + image.ScaleToFit(element.Size.Width, element.Size.Height); + + document.Add(image); + } + + private void DrawTable(Document document, LayoutElement element, ReportContext context) + { + // 创建表格 + var table = new PdfPTable(3); // 假设3列 + table.WidthPercentage = 100; + + // 添加表头 + table.AddCell(new PdfPCell(new Phrase("参数", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)))); + table.AddCell(new PdfPCell(new Phrase("测量值", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)))); + table.AddCell(new PdfPCell(new Phrase("标准值", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)))); + + // 添加数据行 + foreach (var measurement in context.Measurements) + { + table.AddCell(new PdfPCell(new Phrase(measurement.Parameter))); + table.AddCell(new PdfPCell(new Phrase(measurement.Value.ToString()))); + table.AddCell(new PdfPCell(new Phrase(measurement.StandardValue.ToString()))); + } + + document.Add(table); + } +} +``` + +## 四、最佳实践与建议 + +### 1. 性能优化 + +- **图像处理**: 对大尺寸图像进行**压缩和缩放**,避免PDF文件过大 +- **内存管理**: 使用`using`语句确保资源及时释放 +- **批量处理**: 对大量数据采用**分批处理**策略,避免UI冻结 + +### 2. 错误处理 + +- 实现**完善的异常捕获**机制,特别是图像转换和PDF生成环节 +- 提供**友好的错误提示**,便于问题排查 +- 添加**日志记录**功能,跟踪报告生成过程 + +### 3. 样式管理 + +- 创建**样式库**,统一字体、颜色、间距等 +- 支持**主题切换**,适应不同客户的品牌要求 +- 确保**打印友好**,考虑黑白打印时的可读性 + +### 4. 扩展性考虑 + +- **插件架构**: 设计可扩展的插件系统,便于添加新功能 +- **多格式输出**: 基于相同架构,扩展支持Word、Excel等格式输出 +- **云服务集成**: 考虑与云存储集成,自动上传生成的报告 + +通过以上设计,XP.ReportEngine将成为一个**灵活、高效、可维护**的PDF报告生成系统,满足工业CT检测报告的专业需求,同时保持系统的扩展性和易用性。 diff --git a/XP.ReportEngine/Documents/XP.ReportEngineModelDefine.md b/XP.ReportEngine/Documents/XP.ReportEngineModelDefine.md new file mode 100644 index 0000000..a5d96a6 --- /dev/null +++ b/XP.ReportEngine/Documents/XP.ReportEngineModelDefine.md @@ -0,0 +1,328 @@ +# XP.ReportEngine 模板定义规范 + +## **一、模板结构总览** + +模板使用JSON格式定义,分为以下几个核心部分: + +1.  + +`document`:文档基础配置(页面尺寸、边距等)。 + +2.  + +`pages`:页面列表,每个页面包含元素列表。 + +3.  + +`elements`:页面中的具体元素(文本、表格、图片等)。 + +4.  + +`styles`:预定义的样式,可复用。 + +5.  + +`dataKey`:数据绑定字段,关联业务数据。 + +## **二、首页布局规范** + +**模板路径**:`Templates/Homepage.json` + +代码图标/24_new/复制 + +``` +{ + "document": { + "pageSize": "A4", + "orientation": "Portrait", + "margins": { "top": 30, "right": 20, "bottom": 20, "left": 20 } + }, + "pages": [ + { + "type": "homepage", + "elements": [ + { "type": "text", "content": "平面CT检测报告", "style": "title", "position": [10, 10] }, + { "type": "text", "content": "报告编号:${reportId}", "style": "subtitle", "position": [10, 40] }, + { "type": "text", "content": "检测日期:${inspectionDate}", "style": "subtitle", "position": [10, 60] }, + { "type": "text", "content": "样品名称:${sampleName}", "style": "subtitle", "position": [10, 80] }, + { "type": "divider", "position": [10, 100], "width": 190 }, + { "type": "table", "dataKey": "summaryData", "columns": [...], "position": [10, 120], "size": [190, 60] } + ] + } + ], + "styles": { + // ... 样式定义(见下文) + } +} +``` + +**关键要素说明**: + +1.  + +**标题与元数据**:顶部显示报告标题、编号、日期和样品名称。 + +2.  + +**摘要表格**:显示关键统计信息(如缺陷数量、合格率等),通过`summaryData`绑定数据。 + +3.  + +**分隔线**:视觉分隔标题与主体内容。 + +## **三、测量数据布局规范** + +**模板路径**:`Templates/MetricData.json` + +代码图标/24_new/复制 + +``` +{ + "pages": [ + { + "type": "metricData", + "elements": [ + { "type": "text", "content": "测量数据详情", "style": "sectionTitle", "position": [10, 10] }, + { "type": "table", "dataKey": "measurements", "columns": [ + { "header": "参数名称", "field": "parameter" }, + { "header": "测量值", "field": "value" }, + { "header": "单位", "field": "unit" } + ], "position": [10, 30], "size": [190, 100] } + ] + } + ], + "styles": { + // ... 样式定义(见下文) + } +} +``` + +**关键要素说明**: + +●  + +表格绑定`measurements`数据,列通过`field`属性绑定数据字段。 + +●  + +支持动态行数,自动调整表格高度。 + +## **四、缺陷检测布局规范** + +**模板路径**:`Templates/DefectDetails.json` + +代码图标/24_new/复制 + +``` +{ + "pages": [ + { + "type": "defectDetails", + "elements": [ + { "type": "text", "content": "缺陷检测结果", "style": "sectionTitle", "position": [10, 10] }, + { + "type": "grid", "dataKey": "defects", + "columns": [ + { "type": "image", "dataKey": "imagePath", "size": [90, 90], "border": true }, + { "type": "text", "content": "缺陷类型:${type}", "style": "gridText", "width": 100 }, + { "type": "text", "content": "位置:X=${x}, Y=${y}", "style": "gridText", "width": 100 } + ], + "position": [10, 30], "colWidth": 100, "rowHeight": 100 + } + ] + } + ], + "styles": { + "gridText": { "font": "Arial", "size": 10, "align": "left" } + } +} +``` + +**关键要素说明**: + +1.  + +**网格布局**:每行显示缺陷图片、类型和位置信息。 + +2.  + +使用`grid`元素自动排版多缺陷数据,支持水平滚动或分页。 + +3.  + +图片路径通过`imagePath`字段绑定,文本使用数据绑定语法(如`X=${x}`)。 + +## **五、BGA检测布局规范** + +**模板路径**:`Templates/BGAInspection.json` + +代码图标/24_new/复制 + +``` +{ + "pages": [ + { + "type": "bgaDetails", + "elements": [ + { "type": "text", "content": "BGA焊点检测结果", "style": "sectionTitle", "position": [10, 10] }, + { + "type": "image", "dataKey": "bgaTopViewImage", "position": [10, 30], "size": [190, 150], "border": true, + "annotations": [ + { "type": "point", "x": ${defectX}, "y": ${defectY}, "color": "red", "size": 5 } + ] + }, + { + "type": "table", "dataKey": "bgaMetrics", + "columns": [ "引脚编号", "焊锡高度", "偏移量" ], + "position": [10, 190], "size": [190, 80] + } + ] + } + ] +} +``` + +**关键要素说明**: + +1.  + +**图片标注**:在BGA俯视图上标记缺陷位置(通过`annotations`)。 + +2.  + +**表格显示参数**:焊锡高度、偏移量等数据。 + +3.  + +支持动态标注点,绑定缺陷坐标数据。 + +## **六、气泡检测布局规范** + +**模板路径**:`Templates/VoidInspection.json` + +代码图标/24_new/复制 + +``` +{ + "pages": [ + { + "type": "voidDetails", + "elements": [ + { "type": "text", "content": "气泡检测结果", "style": "sectionTitle", "position": [10, 10] }, + { + "type": "image", "dataKey": "voidImage", "position": [10, 30], "size": [190, 150], "border": true, + "annotations": [ + { "type": "circle", "x": ${bubbleX}, "y": ${bubbleY}, "radius": ${bubbleRadius}, "color": "blue" } + ] + }, + { "type": "text", "content": "总气泡数:${voidCount}", "style": "resultText", "position": [10, 190] }, + { "type": "text", "content": "最大气泡体积:${maxVoidVolume} mm³", "style": "resultText", "position": [10, 210] } + ] + } + ], + "styles": { + "resultText": { "font": "Arial", "size": 14, "bold": true } + } +} +``` + +**关键要素说明**: + +1.  + +**气泡可视化**:在图像上用圆形标注气泡位置、半径。 + +2.  + +**统计结果**:显示总数量、最大体积等关键指标。 + +3.  + +支持多气泡标注,数据绑定气泡坐标和尺寸。 + +## **七、通孔填锡率检测布局规范** + +**模板路径**:`Templates/ViaFillInspection.json` + +代码图标/24_new/复制 + +``` +{ + "pages": [ + { + "type": "viaFillDetails", + "elements": [ + { "type": "text", "content": "通孔填锡率检测结果", "style": "sectionTitle", "position": [10, 10] }, + { + "type": "image", "dataKey": "viaImage", "position": [10, 30], "size": [190, 150], "border": true, + "annotations": [ + { "type": "rectangle", "x": ${viaX}, "y": ${viaY}, "width": ${viaWidth}, "height": ${viaHeight}, "color": "green" } + ] + }, + { "type": "text", "content": "平均填锡率:${avgFillRate}%", "style": "resultText", "position": [10, 190] }, + { "type": "progressBar", "value": ${avgFillRate}, "position": [10, 220], "size": [190, 20], "color": "${fillRateColor(avgFillRate)}" } + ] + } + ], + "functions": { + "fillRateColor(value)": "return value >= 90 ? 'green' : value >= 70 ? 'orange' : 'red';" + } +} +``` + +**关键要素说明**: + +1.  + +**填锡率图示**:用矩形标注通孔位置,进度条显示填锡率。 + +2.  + +**颜色条件绑定**:通过函数`fillRateColor`根据数值动态设置颜色。 + +3.  + +支持多通孔标注,绑定位置和尺寸数据。 + +## **八、样式定义示例** + +代码图标/24_new/复制 + +``` +"styles": { + "title": { "font": "Arial", "size": 24, "bold": true, "color": "#000000" }, + "subtitle": { "font": "Arial", "size": 16, "italic": true, "color": "#666666" }, + "gridText": { "font": "Arial", "size": 10, "align": "left" }, + "resultText": { "font": "Arial", "size": 14, "bold": true } +} +``` + +**关键要素说明**: + +●  + +样式可复用,通过`style`属性引用。 + +●  + +支持字体、大小、颜色、对齐等属性配置。 + +**# 总结** + +●  + +**模块化设计**:各检测模块独立为单独模板文件,可灵活组合。 + +●  + +**数据绑定**:通过`${}`语法绑定业务数据(如`measurements`、`defects`等对象)。 + +●  + +**动态布局**:支持表格自适应高度、图片标注、条件样式等高级功能。 + +●  + +**可扩展性**:新增检测类型只需定义对应模板文件即可。 + +**备注**:实际使用时,需根据具体业务数据模型调整`dataKey`和字段名称,确保模板与输入数据匹配。 diff --git a/XP.ReportEngine/Interfaces/IDataBinder.cs b/XP.ReportEngine/Interfaces/IDataBinder.cs new file mode 100644 index 0000000..7063ff8 --- /dev/null +++ b/XP.ReportEngine/Interfaces/IDataBinder.cs @@ -0,0 +1,18 @@ +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Interfaces +{ + /// + /// 数据绑定器接口 | Data binder interface + /// + public interface IDataBinder + { + /// + /// 将上下文数据绑定到模板 | Bind context data to template + /// + /// 报告模板 | Report template + /// 报告上下文 | Report context + /// 绑定后的模板(元素内容已替换)| Bound template with resolved content + ReportTemplate Bind(ReportTemplate template, ReportContext context); + } +} diff --git a/XP.ReportEngine/Interfaces/ILayoutEngine.cs b/XP.ReportEngine/Interfaces/ILayoutEngine.cs new file mode 100644 index 0000000..732ff3e --- /dev/null +++ b/XP.ReportEngine/Interfaces/ILayoutEngine.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Interfaces +{ + /// + /// 排版引擎接口 | Layout engine interface + /// + public interface ILayoutEngine + { + /// + /// 计算页面布局 | Calculate page layout + /// + /// 绑定后的模板 | Bound template + /// 生成选项 | Generation options + /// 排版后的页面列表 | List of laid-out pages + List CalculateLayout(ReportTemplate template, ReportGenerationOptions options); + } +} diff --git a/XP.ReportEngine/Interfaces/IPdfRenderer.cs b/XP.ReportEngine/Interfaces/IPdfRenderer.cs new file mode 100644 index 0000000..3679c0a --- /dev/null +++ b/XP.ReportEngine/Interfaces/IPdfRenderer.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.IO; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Interfaces +{ + /// + /// PDF 渲染器接口 | PDF renderer interface + /// + public interface IPdfRenderer + { + /// + /// 将排版结果渲染为 PDF | Render layout result to PDF + /// + /// 排版后的页面列表 | Laid-out pages + /// 生成选项 | Generation options + /// 绑定后的模板(用于页眉页脚配置)| Bound template (for header/footer config) + /// PDF 内存流 | PDF memory stream + MemoryStream Render(List pages, ReportGenerationOptions options, ReportTemplate template = null); + } +} diff --git a/XP.ReportEngine/Interfaces/IReportDataAdapter.cs b/XP.ReportEngine/Interfaces/IReportDataAdapter.cs new file mode 100644 index 0000000..264ab7c --- /dev/null +++ b/XP.ReportEngine/Interfaces/IReportDataAdapter.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Interfaces +{ + /// + /// 报告数据适配器接口 | Report data adapter interface + /// 将 XP.ImageProcessing 的 OutputData 转换为 ReportContext + /// + public interface IReportDataAdapter + { + /// + /// 将处理器输出数据适配为报告上下文 | Adapt processor output data to report context + /// + /// 处理器输出字典列表 | List of processor output dictionaries + /// 报告元数据 | Report metadata + /// 报告上下文 | Report context + ReportContext Adapt(List processorOutputs, ReportMetadata metadata); + } +} diff --git a/XP.ReportEngine/Interfaces/IReportGenerator.cs b/XP.ReportEngine/Interfaces/IReportGenerator.cs new file mode 100644 index 0000000..4d2e15d --- /dev/null +++ b/XP.ReportEngine/Interfaces/IReportGenerator.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Interfaces +{ + /// + /// 报告生成器接口(格式无关)| Report generator interface (format-agnostic) + /// + public interface IReportGenerator + { + /// + /// 异步生成报告 | Generate report asynchronously + /// + /// 报告上下文数据 | Report context data + /// 生成选项 | Generation options + /// 生成结果 | Generation result + Task GenerateAsync(ReportContext context, ReportGenerationOptions options); + } +} diff --git a/XP.ReportEngine/Interfaces/IReportGeneratorFactory.cs b/XP.ReportEngine/Interfaces/IReportGeneratorFactory.cs new file mode 100644 index 0000000..56f1d72 --- /dev/null +++ b/XP.ReportEngine/Interfaces/IReportGeneratorFactory.cs @@ -0,0 +1,15 @@ +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Interfaces +{ + /// + /// 报告生成器工厂接口 | Report generator factory interface + /// + public interface IReportGeneratorFactory + { + /// + /// 根据输出格式创建生成器 | Create generator by output format + /// + IReportGenerator Create(ReportOutputFormat format); + } +} diff --git a/XP.ReportEngine/Interfaces/IReportService.cs b/XP.ReportEngine/Interfaces/IReportService.cs new file mode 100644 index 0000000..8b8d63f --- /dev/null +++ b/XP.ReportEngine/Interfaces/IReportService.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Interfaces +{ + /// + /// 报告服务接口(门面)| Report service interface (Facade) + /// 提供完整的报告生成流程,外部模块通过此接口调用报告功能 + /// Provides complete report generation workflow for external modules + /// + /// + /// 使用示例 | Usage example: + /// + /// var request = new ReportRequest + /// { + /// ProcessorOutputs = processorOutputs, + /// Metadata = new ReportMetadata + /// { + /// SampleName = "PCB-001", + /// OperatorName = "Operator", + /// InspectionDate = DateTime.Now + /// } + /// }; + /// var result = await _reportService.GenerateAsync(request); + /// + /// + public interface IReportService + { + /// + /// 生成报告 | Generate report + /// 执行完整流程:生成报告ID → 数据适配 → 上下文组装 → 管线生成 → 文件保存 + /// Executes full workflow: generate report ID → data adaptation → context assembly → pipeline generation → file saving + /// + /// 报告生成请求 | Report generation request + /// 报告生成结果 | Report generation result + Task GenerateAsync(ReportRequest request); + + /// + /// 预热报告引擎(建议在应用启动后台调用)| Warm up report engine (recommended to call in background on app startup) + /// 触发 iText7 初始化、字体加载、JIT 编译等一次性开销,避免首次生成报告时卡顿 + /// Triggers iText7 initialization, font loading, JIT compilation to avoid first-run latency + /// + Task WarmUpAsync(); + } +} diff --git a/XP.ReportEngine/Interfaces/ITemplateEngine.cs b/XP.ReportEngine/Interfaces/ITemplateEngine.cs new file mode 100644 index 0000000..7596ab4 --- /dev/null +++ b/XP.ReportEngine/Interfaces/ITemplateEngine.cs @@ -0,0 +1,22 @@ +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Interfaces +{ + /// + /// 模板引擎接口 | Template engine interface + /// + public interface ITemplateEngine + { + /// + /// 加载并验证模板 | Load and validate template + /// + /// 模板文件路径 | Template file path + /// 解析后的模板对象 | Parsed template object + ReportTemplate LoadTemplate(string templatePath); + + /// + /// 验证模板结构完整性 | Validate template structure integrity + /// + TemplateValidationResult Validate(ReportTemplate template); + } +} diff --git a/XP.ReportEngine/Models/ImageData.cs b/XP.ReportEngine/Models/ImageData.cs new file mode 100644 index 0000000..b1aa0ed --- /dev/null +++ b/XP.ReportEngine/Models/ImageData.cs @@ -0,0 +1,35 @@ +namespace XP.ReportEngine.Models +{ + /// + /// 图像数据封装 | Image data wrapper + /// + public class ImageData + { + /// + /// 图像来源类型 | Image source type + /// + public ImageSourceType SourceType { get; set; } + + /// + /// 字节数组数据(当 SourceType 为 Bytes 时)| Byte array data + /// + public byte[] Bytes { get; set; } + + /// + /// 文件路径(当 SourceType 为 FilePath 时)| File path + /// + public string FilePath { get; set; } + + /// + /// BitmapSource 引用(当 SourceType 为 BitmapSource 时)| BitmapSource reference + /// + public object BitmapSource { get; set; } + } + + public enum ImageSourceType + { + Bytes, + FilePath, + BitmapSource + } +} diff --git a/XP.ReportEngine/Models/LayoutPage.cs b/XP.ReportEngine/Models/LayoutPage.cs new file mode 100644 index 0000000..9abcac2 --- /dev/null +++ b/XP.ReportEngine/Models/LayoutPage.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; + +namespace XP.ReportEngine.Models +{ + /// + /// 排版后的页面 | Laid-out page + /// + public class LayoutPage + { + public int PageNumber { get; set; } + + /// + /// 页面类型(来自模板定义:homepage / metricData / bgaInspection 等) + /// Page type from template definition + /// + public string PageType { get; set; } + + public List Elements { get; set; } = new(); + } + + /// + /// 排版后的元素(含计算后的绝对坐标)| Laid-out element with computed absolute coordinates + /// + public class LayoutElement + { + public TemplateElement Source { get; set; } + public float X { get; set; } + public float Y { get; set; } + public float Width { get; set; } + public float Height { get; set; } + public StyleDefinition ResolvedStyle { get; set; } + public string ResolvedContent { get; set; } + public List> ResolvedTableData { get; set; } + public ImageData ResolvedImage { get; set; } + } +} diff --git a/XP.ReportEngine/Models/ProcessorOutput.cs b/XP.ReportEngine/Models/ProcessorOutput.cs new file mode 100644 index 0000000..3594ad7 --- /dev/null +++ b/XP.ReportEngine/Models/ProcessorOutput.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace XP.ReportEngine.Models +{ + /// + /// 处理器输出数据封装 | Processor output data wrapper + /// + public class ProcessorOutput + { + /// + /// 处理器类型名称 | Processor type name + /// + public string ProcessorType { get; set; } + + /// + /// 输出数据字典 | Output data dictionary + /// + public Dictionary OutputData { get; set; } = new(); + + /// + /// 关联的已标注图像 | Associated annotated image + /// + public ImageData AnnotatedImage { get; set; } + } +} diff --git a/XP.ReportEngine/Models/ReportContext.cs b/XP.ReportEngine/Models/ReportContext.cs new file mode 100644 index 0000000..6b08c73 --- /dev/null +++ b/XP.ReportEngine/Models/ReportContext.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +namespace XP.ReportEngine.Models +{ + /// + /// 报告上下文,包含生成报告所需的全部数据 | Report context containing all data needed for report generation + /// + public class ReportContext + { + /// + /// 报告元数据 | Report metadata + /// + public ReportMetadata Metadata { get; set; } + + /// + /// 检测结果数据集合(按处理器类型分组)| Inspection result data grouped by processor type + /// + public List ResultGroups { get; set; } = new(); + + /// + /// 图像数据字典(键为 dataKey,值为图像数据)| Image data dictionary (key=dataKey, value=image data) + /// + public Dictionary Images { get; set; } = new(); + + /// + /// 自定义属性字典(用于数据绑定的扁平化键值对)| Custom properties for data binding + /// + public Dictionary Properties { get; set; } = new(); + } + + /// + /// 报告元数据 | Report metadata + /// + public class ReportMetadata + { + public string ReportId { get; set; } + public DateTime InspectionDate { get; set; } + public string SampleName { get; set; } + public string OperatorName { get; set; } + public string Description { get; set; } + } + + /// + /// 检测结果分组 | Inspection result group + /// + public class InspectionResultGroup + { + /// + /// 处理器类型标识 | Processor type identifier + /// + public string ProcessorType { get; set; } + + /// + /// 数据来源标识 | Data source identifier + /// + public string SourceId { get; set; } + + /// + /// 分类结果(Pass/Fail)| Classification result + /// + public string Classification { get; set; } + + /// + /// 结果键值对 | Result key-value pairs + /// + public Dictionary Data { get; set; } = new(); + + /// + /// 表格数据行(用于表格渲染)| Table data rows for table rendering + /// + public List> TableRows { get; set; } = new(); + } +} diff --git a/XP.ReportEngine/Models/ReportGenerationOptions.cs b/XP.ReportEngine/Models/ReportGenerationOptions.cs new file mode 100644 index 0000000..a111849 --- /dev/null +++ b/XP.ReportEngine/Models/ReportGenerationOptions.cs @@ -0,0 +1,30 @@ +namespace XP.ReportEngine.Models +{ + /// + /// 报告生成选项 | Report generation options + /// + public class ReportGenerationOptions + { + /// + /// 模板文件路径 | Template file path + /// + public string TemplatePath { get; set; } + + /// + /// 输出文件路径(可选,为 null 时仅返回 MemoryStream)| Output file path (optional) + /// + public string OutputFilePath { get; set; } + + /// + /// 输出格式 | Output format + /// + public ReportOutputFormat Format { get; set; } = ReportOutputFormat.Pdf; + } + + public enum ReportOutputFormat + { + Pdf, + Excel, + Csv + } +} diff --git a/XP.ReportEngine/Models/ReportRequest.cs b/XP.ReportEngine/Models/ReportRequest.cs new file mode 100644 index 0000000..0c3f50a --- /dev/null +++ b/XP.ReportEngine/Models/ReportRequest.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; + +namespace XP.ReportEngine.Models +{ + /// + /// 报告生成请求 | Report generation request + /// 封装外部调用方生成报告所需的全部输入参数 + /// Encapsulates all input parameters needed by external callers to generate a report + /// + public class ReportRequest + { + /// + /// 处理器输出数据列表 | List of processor output data + /// + public List ProcessorOutputs { get; set; } = new(); + + /// + /// 报告元数据(产品名、操作员、描述等)| Report metadata (product name, operator, description, etc.) + /// + public ReportMetadata Metadata { get; set; } + + /// + /// 额外图像数据(如工件整体图、自定义图像)| Additional image data (e.g., workpiece overview, custom images) + /// 键为 dataKey,值为图像数据 + /// Key is dataKey, value is image data + /// + public Dictionary AdditionalImages { get; set; } = new(); + + /// + /// 输出文件路径(可选)| Output file path (optional) + /// 为空时根据 ReportConfig 和 FileNameParameters 自动生成 + /// When empty, auto-generated based on ReportConfig and FileNameParameters + /// + public string OutputFilePath { get; set; } + + /// + /// 文件名占位符参数(可选)| File name placeholder parameters (optional) + /// 用于 ReportConfig.FileNamePattern 中的占位符替换 + /// Used for placeholder replacement in ReportConfig.FileNamePattern + /// + public Dictionary FileNameParameters { get; set; } = new(); + + /// + /// 自定义属性(可选)| Custom properties (optional) + /// 额外的键值对数据,会合并到 ReportContext.Properties 中 + /// Additional key-value data merged into ReportContext.Properties + /// + public Dictionary CustomProperties { get; set; } = new(); + } +} diff --git a/XP.ReportEngine/Models/ReportResult.cs b/XP.ReportEngine/Models/ReportResult.cs new file mode 100644 index 0000000..c95753c --- /dev/null +++ b/XP.ReportEngine/Models/ReportResult.cs @@ -0,0 +1,22 @@ +using System; +using System.IO; + +namespace XP.ReportEngine.Models +{ + /// + /// 报告生成结果 | Report generation result + /// + public class ReportResult + { + public bool IsSuccess { get; set; } + public MemoryStream PdfStream { get; set; } + public string ErrorMessage { get; set; } + public Exception Exception { get; set; } + + public static ReportResult Success(MemoryStream stream) + => new() { IsSuccess = true, PdfStream = stream }; + + public static ReportResult Failure(string message, Exception ex = null) + => new() { IsSuccess = false, ErrorMessage = message, Exception = ex }; + } +} diff --git a/XP.ReportEngine/Models/ReportServiceResult.cs b/XP.ReportEngine/Models/ReportServiceResult.cs new file mode 100644 index 0000000..622a412 --- /dev/null +++ b/XP.ReportEngine/Models/ReportServiceResult.cs @@ -0,0 +1,49 @@ +using System; + +namespace XP.ReportEngine.Models +{ + /// + /// 报告服务结果 | Report service result + /// 封装报告生成的最终结果信息 + /// Encapsulates the final result of report generation + /// + public class ReportServiceResult + { + /// + /// 是否成功 | Whether successful + /// + public bool IsSuccess { get; set; } + + /// + /// 输出文件路径(成功时有值)| Output file path (has value when successful) + /// + public string OutputFilePath { get; set; } + + /// + /// 报告编号 | Report ID + /// + public string ReportId { get; set; } + + /// + /// 错误信息(失败时有值)| Error message (has value when failed) + /// + public string ErrorMessage { get; set; } + + /// + /// 异常对象(失败时有值)| Exception object (has value when failed) + /// + public Exception Exception { get; set; } + + /// + /// 创建成功结果 | Create success result + /// + public static ReportServiceResult Success(string outputFilePath, string reportId) + => new() { IsSuccess = true, OutputFilePath = outputFilePath, ReportId = reportId }; + + /// + /// 创建失败结果 | Create failure result + /// + public static ReportServiceResult Failure(string message, Exception ex = null) + => new() { IsSuccess = false, ErrorMessage = message, Exception = ex }; + } +} diff --git a/XP.ReportEngine/Models/ReportTemplate.cs b/XP.ReportEngine/Models/ReportTemplate.cs new file mode 100644 index 0000000..e2a2218 --- /dev/null +++ b/XP.ReportEngine/Models/ReportTemplate.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; + +namespace XP.ReportEngine.Models +{ + /// + /// 报告模板定义 | Report template definition + /// + public class ReportTemplate + { + public DocumentSettings Document { get; set; } + public List Pages { get; set; } = new(); + public Dictionary Styles { get; set; } = new(); + } + + public class DocumentSettings + { + public string PageSize { get; set; } = "A4"; + public string Orientation { get; set; } = "Portrait"; + public MarginSettings Margins { get; set; } = new(); + + /// + /// 页眉配置(仅内容页显示,首页不显示)| Header config (content pages only, not homepage) + /// + public HeaderFooterSettings Header { get; set; } + + /// + /// 页脚配置(仅内容页显示,首页不显示)| Footer config (content pages only, not homepage) + /// + public HeaderFooterSettings Footer { get; set; } + } + + public class MarginSettings + { + public float Top { get; set; } = 20f; + public float Bottom { get; set; } = 20f; + public float Left { get; set; } = 20f; + public float Right { get; set; } = 20f; + } + + /// + /// 页眉/页脚配置 | Header/Footer settings + /// + public class HeaderFooterSettings + { + /// + /// 是否启用 | Whether enabled + /// + public bool Enabled { get; set; } = true; + + /// + /// 左侧文本行(支持 ${} 绑定表达式)| Left-side text lines with binding expressions + /// + public List Left { get; set; } = new(); + + /// + /// 右侧文本行(支持 ${} 绑定表达式)| Right-side text lines with binding expressions + /// + public List Right { get; set; } = new(); + + /// + /// 右侧图像 dataKey(如 logo)| Right-side image dataKey (e.g. logo) + /// + public string RightImageKey { get; set; } + + /// + /// 左侧图像 dataKey | Left-side image dataKey + /// + public string LeftImageKey { get; set; } + + /// + /// 字体大小 | Font size + /// + public float FontSize { get; set; } = 8f; + + /// + /// 字体颜色 | Font color + /// + public string Color { get; set; } = "#666666"; + + /// + /// 是否显示分隔线 | Whether to show separator line + /// + public bool ShowLine { get; set; } = true; + } + + public class TemplatePage + { + /// + /// 页面类型:homepage / metricData / defectDetails / bgaInspection / voidInspection / viaFillInspection + /// + public string Type { get; set; } + public List Elements { get; set; } = new(); + } +} diff --git a/XP.ReportEngine/Models/TemplateElement.cs b/XP.ReportEngine/Models/TemplateElement.cs new file mode 100644 index 0000000..9b3dd27 --- /dev/null +++ b/XP.ReportEngine/Models/TemplateElement.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; + +namespace XP.ReportEngine.Models +{ + public class TemplateElement + { + /// + /// 元素类型:text / image / table / divider / spacer / row / grid + /// + public string Type { get; set; } + + /// + /// 文本内容(可含 ${} 绑定表达式)| Text content with binding expressions + /// + public string Content { get; set; } + + /// + /// 样式名称引用 | Style name reference + /// + public string Style { get; set; } + + /// + /// 数据绑定键 | Data binding key + /// + public string DataKey { get; set; } + + /// + /// 位置坐标 [x, y](mm)| Position coordinates in mm + /// + public float[] Position { get; set; } + + /// + /// 尺寸 [width, height](mm)| Size in mm + /// + public float[] Size { get; set; } + + /// + /// 表格列定义 | Table column definitions + /// + public List Columns { get; set; } + + /// + /// 是否显示边框 | Whether to show border + /// + public bool Border { get; set; } + + /// + /// 定位方式:absolute / flow | Positioning mode + /// + public string Positioning { get; set; } = "absolute"; + + /// + /// 子元素列表(用于 row 类型的水平布局容器) + /// Child elements (for row type horizontal layout container) + /// + public List Children { get; set; } + + /// + /// 水平对齐方式(用于 row 子元素):left / center / right + /// Horizontal alignment for row children + /// + public string Align { get; set; } + + /// + /// 列宽比例数组(用于 row 类型,如 [7, 3] 表示 7:3 比例) + /// Column width ratios for row type (e.g. [7, 3] means 7:3 ratio) + /// + public float[] Widths { get; set; } + + /// + /// 条件颜色规则(用于 text 元素,根据内容中包含的关键词匹配颜色) + /// Conditional color rules for text elements (match keywords in content to color) + /// 格式:{ "Pass": "#008000", "Fail": "#FF0000" } + /// + public Dictionary ColorRules { get; set; } + + /// + /// 表格数据行(数据绑定阶段填充,用于排版计算和渲染) + /// Table data rows (populated during data binding phase, used for layout calculation and rendering) + /// + [Newtonsoft.Json.JsonIgnore] + public List> TableData { get; set; } + + /// + /// 图像数据(数据绑定阶段填充)| Image data (populated during data binding phase) + /// + [Newtonsoft.Json.JsonIgnore] + public ImageData ImageData { get; set; } + } + + public class ColumnDefinition + { + public string Header { get; set; } + public string Field { get; set; } + public float Width { get; set; } + public string Align { get; set; } = "left"; + + /// + /// 条件颜色规则(根据单元格值匹配颜色) + /// Conditional color rules (match cell value to color) + /// 格式:{ "Pass": "#008000", "Fail": "#FF0000" } + /// + public Dictionary ColorRules { get; set; } + } + + public class StyleDefinition + { + public string Font { get; set; } + public float Size { get; set; } = 12f; + public bool Bold { get; set; } + public bool Italic { get; set; } + public string Color { get; set; } = "#000000"; + public string Align { get; set; } = "left"; + public string BackgroundColor { get; set; } + + /// + /// 上边距(mm)| Top margin in mm + /// + public float MarginTop { get; set; } + + /// + /// 下边距(mm)| Bottom margin in mm + /// + public float MarginBottom { get; set; } + + /// + /// 左缩进(mm)| Left indent/padding in mm + /// + public float PaddingLeft { get; set; } + + /// + /// 行高倍数(1.0 = 单倍行距,1.5 = 1.5倍行距,0 表示使用默认) + /// Line height multiplier (1.0 = single spacing, 1.5 = 1.5x spacing, 0 = use default) + /// + public float LineHeight { get; set; } + } +} diff --git a/XP.ReportEngine/Models/TemplateValidationResult.cs b/XP.ReportEngine/Models/TemplateValidationResult.cs new file mode 100644 index 0000000..6e2191a --- /dev/null +++ b/XP.ReportEngine/Models/TemplateValidationResult.cs @@ -0,0 +1,17 @@ +namespace XP.ReportEngine.Models +{ + /// + /// 模板验证结果 | Template validation result + /// + public class TemplateValidationResult + { + public bool IsValid { get; set; } + public string ErrorMessage { get; set; } + + public static TemplateValidationResult Valid() + => new() { IsValid = true }; + + public static TemplateValidationResult Invalid(string message) + => new() { IsValid = false, ErrorMessage = message }; + } +} diff --git a/XP.ReportEngine/ReportEngineModule.cs b/XP.ReportEngine/ReportEngineModule.cs new file mode 100644 index 0000000..a6cd48a --- /dev/null +++ b/XP.ReportEngine/ReportEngineModule.cs @@ -0,0 +1,98 @@ +using Prism.Ioc; +using Prism.Modularity; +using System.Resources; +using XP.Common.Localization; +using XP.Common.Localization.Interfaces; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Configs; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Services; +using XP.ReportEngine.ViewModels; +using XP.ReportEngine.Views; + +namespace XP.ReportEngine +{ + /// + /// 报告引擎模块 | Report Engine Module + /// Prism 模块入口,注册报告生成相关服务到 DI 容器 + /// Prism module entry, registers report generation services to DI container + /// + [Module(ModuleName = "ReportEngineModule")] + public class ReportEngineModule : IModule + { + /// + /// 模块初始化 | Module initialization + /// 注册模块级多语言资源源 | Register module-level localization resource source + /// + public void OnInitialized(IContainerProvider containerProvider) + { + // 注册模块级多语言资源到 Fallback Chain | Register module-level localization resources to Fallback Chain + var localizationService = containerProvider.Resolve(); + var resourceManager = new ResourceManager( + "XP.ReportEngine.Resources.Resources", + typeof(ReportEngineModule).Assembly); + localizationService.RegisterResourceSource("XP.ReportEngine", resourceManager); + + // 初始化 LocalizationHelper,使其通过 ILocalizationService 获取字符串(支持 Fallback Chain) + // Initialize LocalizationHelper to use ILocalizationService for string lookup (supports Fallback Chain) + LocalizationHelper.Initialize(localizationService); + + // 后台预热报告引擎(触发 iText7 初始化、字体加载、JIT 编译,避免首次生成卡顿) + // Background warm-up report engine (triggers iText7 init, font loading, JIT to avoid first-run latency) + var reportService = containerProvider.Resolve(); + _ = System.Threading.Tasks.Task.Run(() => reportService.WarmUpAsync()); + + System.Console.WriteLine("[ReportEngineModule] 模块已初始化 | Module initialized"); + } + + /// + /// 注册类型到 DI 容器 | Register types to DI container + /// + public void RegisterTypes(IContainerRegistry containerRegistry) + { + // 注册配置加载器(瞬态)| Register config loader (transient) + containerRegistry.Register(); + + // 加载并注册配置为单例 | Load and register config as singleton + containerRegistry.RegisterSingleton(container => + { + var logger = container.Resolve(); + var loader = new Configs.ConfigLoader(logger); + return loader.LoadReportConfig(); + }); + + // 注册报告生成器(瞬态)| Register report generator (transient) + containerRegistry.Register(); + + // 注册报告生成器工厂(单例)| Register report generator factory (singleton) + containerRegistry.RegisterSingleton(); + + // 注册报告服务门面(单例)| Register report service facade (singleton) + containerRegistry.RegisterSingleton(); + + // 注册模板引擎(瞬态)| Register template engine (transient) + containerRegistry.Register(); + + // 注册数据绑定器(瞬态)| Register data binder (transient) + containerRegistry.Register(); + + // 注册排版引擎(瞬态)| Register layout engine (transient) + containerRegistry.Register(); + + // 注册 PDF 渲染器(瞬态)| Register PDF renderer (transient) + containerRegistry.Register(); + + // 注册数据适配器(瞬态)| Register data adapter (transient) + containerRegistry.Register(); + + // 注册报告编号生成器(单例,维护每日计数器状态)| Register report ID generator (singleton, maintains daily counter state) + containerRegistry.RegisterSingleton(); + + // 注册演示窗口 ViewModel 和 View | Register demo window ViewModel and View + containerRegistry.Register(); + containerRegistry.Register(); + + System.Console.WriteLine("[ReportEngineModule] 类型注册完成 | Type registration completed"); + } + } +} diff --git a/XP.ReportEngine/Resources/Resources.en-US.resx b/XP.ReportEngine/Resources/Resources.en-US.resx new file mode 100644 index 0000000..9fe3fc9 --- /dev/null +++ b/XP.ReportEngine/Resources/Resources.en-US.resx @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Inspection Report + + + Inspection Time + + + Product Name + + + Operator + + + Inspection Summary + + + Report ID + + + Description + + + PASS + + + FAIL + + + Line Measurement + + + BGA Void Rate + + + Void Measurement + + + Via Fill Rate + + + No. + + + Void Rate + + + Classification + + + Area + + + Area % + + + Center X + + + Center Y + + + Measurement Type + + + Distance + + + Unit + + + Angle + + + Fill Rate + + + Void Rate + + + Limit + + + Total Defects + + + Pass Count + + + Fail Count + + + Overall Result + + + No Image + + + Inspection Report + + + Measurement Data + + + BGA Solder Ball Inspection + + + Void Inspection + + + Via Fill Rate Inspection + + + Ball Count + + + Total Ball Area + + + Total Void Area + + + Void Rate Limit + + + Ball No. + + + ROI Area + + + Total Void Area + + + Void Count + + + Max Void Area + + + Void Rate Limit + + + Fill Rate + + + Full Distance + + + Fill Distance + + + THT Limit + + + Point 1 + + + Point 2 + + + Result + + + Inspection Type + + + Status + + \ No newline at end of file diff --git a/XP.ReportEngine/Resources/Resources.resx b/XP.ReportEngine/Resources/Resources.resx new file mode 100644 index 0000000..db0c10a --- /dev/null +++ b/XP.ReportEngine/Resources/Resources.resx @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 检测报告 + + + 检测时间 + + + 产品名称 + + + 操作员 + + + 检测摘要 + + + 报告编号 + + + 描述 + + + 通过 + + + 不通过 + + + 距离测量 + + + BGA 气泡率 + + + 空隙测量 + + + 通孔填锡率 + + + 序号 + + + 气泡率 + + + 分类结果 + + + 面积 + + + 面积百分比 + + + 中心 X + + + 中心 Y + + + 测量类型 + + + 距离 + + + 单位 + + + 角度 + + + 填锡率 + + + 气泡率 + + + 限值 + + + 总缺陷数 + + + 通过数量 + + + 不通过数量 + + + 总体结果 + + + 无图像 + + + 检测报告首页 + + + 测量数据 + + + BGA 焊球检测 + + + 空隙检测 + + + 通孔填锡检测 + + + 焊球数量 + + + 焊球总面积 + + + 气泡总面积 + + + 气泡率限值 + + + 焊球序号 + + + ROI 面积 + + + 空隙总面积 + + + 空隙数量 + + + 最大空隙面积 + + + 空隙率限值 + + + 填锡率 + + + 满填距离 + + + 填充距离 + + + THT 限值 + + + 起点 + + + 终点 + + + 结果 + + + 检测类型 + + + 状态 + + \ No newline at end of file diff --git a/XP.ReportEngine/Resources/Resources.zh-CN.resx b/XP.ReportEngine/Resources/Resources.zh-CN.resx new file mode 100644 index 0000000..db0c10a --- /dev/null +++ b/XP.ReportEngine/Resources/Resources.zh-CN.resx @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 检测报告 + + + 检测时间 + + + 产品名称 + + + 操作员 + + + 检测摘要 + + + 报告编号 + + + 描述 + + + 通过 + + + 不通过 + + + 距离测量 + + + BGA 气泡率 + + + 空隙测量 + + + 通孔填锡率 + + + 序号 + + + 气泡率 + + + 分类结果 + + + 面积 + + + 面积百分比 + + + 中心 X + + + 中心 Y + + + 测量类型 + + + 距离 + + + 单位 + + + 角度 + + + 填锡率 + + + 气泡率 + + + 限值 + + + 总缺陷数 + + + 通过数量 + + + 不通过数量 + + + 总体结果 + + + 无图像 + + + 检测报告首页 + + + 测量数据 + + + BGA 焊球检测 + + + 空隙检测 + + + 通孔填锡检测 + + + 焊球数量 + + + 焊球总面积 + + + 气泡总面积 + + + 气泡率限值 + + + 焊球序号 + + + ROI 面积 + + + 空隙总面积 + + + 空隙数量 + + + 最大空隙面积 + + + 空隙率限值 + + + 填锡率 + + + 满填距离 + + + 填充距离 + + + THT 限值 + + + 起点 + + + 终点 + + + 结果 + + + 检测类型 + + + 状态 + + \ No newline at end of file diff --git a/XP.ReportEngine/Resources/Resources.zh-TW.resx b/XP.ReportEngine/Resources/Resources.zh-TW.resx new file mode 100644 index 0000000..9107ec1 --- /dev/null +++ b/XP.ReportEngine/Resources/Resources.zh-TW.resx @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 檢測報告 + + + 檢測時間 + + + 樣品名稱 + + + 操作員 + + + 檢測摘要 + + + 報告編號 + + + 描述 + + + + 通過 + + + 不通過 + + + + 距離測量 + + + BGA 氣泡率 + + + 空隙測量 + + + 通孔填錫率 + + + + 序號 + + + 氣泡率 + + + 分類結果 + + + 面積 + + + 面積百分比 + + + 中心 X + + + 中心 Y + + + + 測量類型 + + + 距離 + + + 單位 + + + 角度 + + + 填錫率 + + + 氣泡率 + + + 限值 + + + + 總缺陷數 + + + 通過數量 + + + 不通過數量 + + + 總體結果 + + + + 無圖像 + + + + 檢測報告首頁 + + + 測量數據 + + + BGA 焊球檢測 + + + 空隙檢測 + + + 通孔填錫檢測 + + + + 焊球數量 + + + 焊球總面積 + + + 氣泡總面積 + + + 氣泡率限值 + + + 焊球序號 + + + + ROI 面積 + + + 空隙總面積 + + + 空隙數量 + + + 最大空隙面積 + + + 空隙率限值 + + + + 填錫率 + + + 滿填距離 + + + 填充距離 + + + THT 限值 + + + + 起點 + + + 終點 + + + 結果 + + + 檢測類型 + + + 狀態 + + diff --git a/XP.ReportEngine/Services/ExpressionDataBinder.cs b/XP.ReportEngine/Services/ExpressionDataBinder.cs new file mode 100644 index 0000000..a3ce3a8 --- /dev/null +++ b/XP.ReportEngine/Services/ExpressionDataBinder.cs @@ -0,0 +1,460 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using System.Text.RegularExpressions; +using Newtonsoft.Json; +using XP.Common.Localization.Enums; +using XP.Common.Localization.Interfaces; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Services +{ + /// + /// 表达式数据绑定器实现 | Expression data binder implementation + /// 支持 ${} 语法的数据绑定、格式化函数和本地化键解析 + /// Supports ${} syntax data binding, format functions and localization key resolution + /// + public class ExpressionDataBinder : IDataBinder + { + private readonly ILoggerService _logger; + private readonly ILocalizationService _localizationService; + + private static readonly Regex ExpressionPattern = new(@"\$\{([^}]+)\}", RegexOptions.Compiled); + private static readonly Regex LocalizationPattern = new(@"^loc:(.+)$", RegexOptions.Compiled); + private static readonly Regex FunctionPattern = new(@"^(\w+)\((.+)\)$", RegexOptions.Compiled); + private static readonly Regex IndexPattern = new(@"^([^\[]+)\[(\d+)\]$", RegexOptions.Compiled); + + public ExpressionDataBinder(ILoggerService logger, ILocalizationService localizationService) + { + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); + } + + public ReportTemplate Bind(ReportTemplate template, ReportContext context) + { + if (template == null) throw new ArgumentNullException(nameof(template)); + if (context == null) throw new ArgumentNullException(nameof(context)); + + _logger.Info("开始数据绑定 | Starting data binding"); + var clonedTemplate = DeepClone(template); + + if (clonedTemplate.Pages != null) + { + foreach (var page in clonedTemplate.Pages) + { + if (page.Elements == null) continue; + foreach (var element in page.Elements) + { + BindElement(element, context); + } + } + } + + // 绑定页眉页脚中的表达式 | Bind expressions in header/footer + BindHeaderFooter(clonedTemplate, context); + + _logger.Info("数据绑定完成 | Data binding completed"); + return clonedTemplate; + } + + + private void BindElement(TemplateElement element, ReportContext context) + { + // 文本内容绑定 | Text content binding + if (!string.IsNullOrEmpty(element.Content)) + { + element.Content = ResolveAllExpressions(element.Content, context); + } + + // 图像元素绑定:通过 DataKey 从 ReportContext.Images 获取 ImageData + // Image element binding: get ImageData from ReportContext.Images via DataKey + if (string.Equals(element.Type, "image", StringComparison.OrdinalIgnoreCase) + && !string.IsNullOrEmpty(element.DataKey) + && context.Images != null + && context.Images.TryGetValue(element.DataKey, out var imageData)) + { + element.ImageData = imageData; + } + + // 表格数据绑定:通过 DataKey 从 ReportContext.Properties 获取表格行数据 + // Table data binding: get table row data from ReportContext.Properties via DataKey + if (string.Equals(element.Type, "table", StringComparison.OrdinalIgnoreCase) + && !string.IsNullOrEmpty(element.DataKey) + && context.Properties != null + && context.Properties.TryGetValue(element.DataKey, out var tableValue) + && tableValue is List> tableRows) + { + element.TableData = tableRows; + } + + // 表格列头绑定 | Table column header binding + if (element.Columns != null) + { + foreach (var column in element.Columns) + { + if (!string.IsNullOrEmpty(column.Header)) + { + column.Header = ResolveAllExpressions(column.Header, context); + } + } + } + + // Row 子元素递归绑定 | Recursively bind row child elements + if (string.Equals(element.Type, "row", StringComparison.OrdinalIgnoreCase) + && element.Children != null) + { + foreach (var child in element.Children) + { + BindElement(child, context); + // Column 子元素递归绑定 | Recursively bind column child elements + if (string.Equals(child.Type, "column", StringComparison.OrdinalIgnoreCase) + && child.Children != null) + { + foreach (var subChild in child.Children) + { + BindElement(subChild, context); + } + } + } + } + } + + /// + /// 绑定页眉页脚中的 ${} 表达式 | Bind ${} expressions in header/footer + /// + private void BindHeaderFooter(ReportTemplate template, ReportContext context) + { + if (template?.Document == null) return; + + // 绑定页眉文本 | Bind header text + if (template.Document.Header != null && template.Document.Header.Enabled) + { + BindStringList(template.Document.Header.Left, context); + BindStringList(template.Document.Header.Right, context); + } + + // 绑定页脚文本 | Bind footer text + if (template.Document.Footer != null && template.Document.Footer.Enabled) + { + BindStringList(template.Document.Footer.Left, context); + BindStringList(template.Document.Footer.Right, context); + } + } + + /// + /// 绑定字符串列表中的表达式 | Bind expressions in string list + /// + private void BindStringList(List lines, ReportContext context) + { + if (lines == null) return; + for (int i = 0; i < lines.Count; i++) + { + if (!string.IsNullOrEmpty(lines[i])) + { + lines[i] = ResolveAllExpressions(lines[i], context); + } + } + } + + private string ResolveAllExpressions(string input, ReportContext context) + { + return ExpressionPattern.Replace(input, match => + { + var expression = match.Groups[1].Value.Trim(); + return ResolveExpression(expression, context); + }); + } + + private string ResolveExpression(string expression, ReportContext context) + { + // 1. 本地化键 loc:ResourceKey | Localization key + var locMatch = LocalizationPattern.Match(expression); + if (locMatch.Success) + { + var resourceKey = locMatch.Groups[1].Value.Trim(); + return ResolveLocalizationKey(resourceKey); + } + + // 2. 格式化函数 functionName(params) | Format function + var funcMatch = FunctionPattern.Match(expression); + if (funcMatch.Success) + { + var functionName = funcMatch.Groups[1].Value; + var paramExpression = funcMatch.Groups[2].Value.Trim(); + return ResolveFormatFunction(functionName, paramExpression, context); + } + + // 3. 属性路径 | Property path + return ResolvePropertyPath(expression, context); + } + + private string ResolveLocalizationKey(string resourceKey) + { + try + { + var value = _localizationService.GetString(resourceKey); + if (value == null) + { + _logger.Warn("本地化键未找到: {Key} | Localization key not found: {Key}", resourceKey); + return string.Empty; + } + return value; + } + catch (Exception ex) + { + _logger.Warn("解析本地化键失败: {Key}, 错误: {Message} | Failed to resolve localization key: {Key}, error: {Message}", resourceKey, ex.Message); + return string.Empty; + } + } + + + private string ResolveFormatFunction(string functionName, string paramExpression, ReportContext context) + { + switch (functionName.ToLowerInvariant()) + { + case "formatdate": + { + var value = ResolvePropertyValue(paramExpression, context); + return FormatDate(value); + } + case "formatnumber": + { + var parts = paramExpression.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + var value = ResolvePropertyValue(parts[0].Trim(), context); + var decimals = parts.Length > 1 && int.TryParse(parts[1].Trim(), out var d) ? d : 2; + return FormatNumber(value, decimals); + } + case "formatpercent": + { + var value = ResolvePropertyValue(paramExpression, context); + return FormatPercent(value); + } + default: + { + _logger.Warn("未知的格式化函数: {FunctionName} | Unknown format function: {FunctionName}", functionName); + return string.Empty; + } + } + } + + private string ResolvePropertyPath(string path, ReportContext context) + { + var value = ResolvePropertyValue(path, context); + if (value == null) + { + _logger.Warn("绑定属性未找到: {Path},替换为空字符串 | Binding property not found: {Path}, replacing with empty string", path); + return string.Empty; + } + return ConvertToString(value); + } + + private object ResolvePropertyValue(string path, ReportContext context) + { + if (string.IsNullOrWhiteSpace(path)) return null; + path = path.Trim(); + + // 优先从 Properties 字典查找 | First look up in Properties dictionary + if (context.Properties != null && context.Properties.TryGetValue(path, out var directValue)) + { + return directValue; + } + + // 尝试从 context 对象解析嵌套路径 | Try nested path from context object + var resolved = ResolveNestedPath(path, context); + return resolved; + } + + + private object ResolveNestedPath(string path, object root) + { + if (root == null || string.IsNullOrWhiteSpace(path)) return null; + + var segments = path.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + var current = root; + + foreach (var segment in segments) + { + if (current == null) return null; + + var indexMatch = IndexPattern.Match(segment); + if (indexMatch.Success) + { + var propertyName = indexMatch.Groups[1].Value; + var index = int.Parse(indexMatch.Groups[2].Value); + current = GetPropertyValue(current, propertyName); + if (current == null) return null; + current = GetIndexedValue(current, index); + } + else + { + current = GetPropertyValue(current, segment); + } + } + + return current; + } + + private object GetPropertyValue(object obj, string propertyName) + { + if (obj == null || string.IsNullOrWhiteSpace(propertyName)) return null; + + // 字典访问 | Dictionary access + if (obj is IDictionary dict) + { + if (dict.TryGetValue(propertyName, out var dictValue)) + return dictValue; + foreach (var kvp in dict) + { + if (string.Equals(kvp.Key, propertyName, StringComparison.OrdinalIgnoreCase)) + return kvp.Value; + } + return null; + } + + // 反射获取属性 | Reflection property access + var type = obj.GetType(); + var propInfo = type.GetProperty(propertyName, + BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); + if (propInfo != null) + { + try { return propInfo.GetValue(obj); } + catch { return null; } + } + + return null; + } + + private object GetIndexedValue(object obj, int index) + { + if (obj == null || index < 0) return null; + + if (obj is IList list) + { + return index < list.Count ? list[index] : null; + } + + if (obj is IEnumerable enumerable) + { + var i = 0; + foreach (var item in enumerable) + { + if (i == index) return item; + i++; + } + } + + return null; + } + + + private string FormatDate(object value) + { + if (value == null) return string.Empty; + + DateTime dateTime; + if (value is DateTime dt) + { + dateTime = dt; + } + else if (DateTime.TryParse(value.ToString(), out var parsed)) + { + dateTime = parsed; + } + else + { + _logger.Warn("无法将值转换为日期: {Value} | Cannot convert value to date: {Value}", value); + return value.ToString(); + } + + var format = _localizationService.CurrentLanguage switch + { + SupportedLanguage.ZhCN => "yyyy年MM月dd日 HH:mm:ss", + SupportedLanguage.ZhTW => "yyyy年MM月dd日 HH:mm:ss", + SupportedLanguage.EnUS => "MM/dd/yyyy HH:mm:ss", + _ => "yyyy-MM-dd HH:mm:ss" + }; + + return dateTime.ToString(format); + } + + private string FormatNumber(object value, int decimals) + { + if (value == null) return string.Empty; + + if (!TryConvertToDouble(value, out var number)) + { + _logger.Warn("无法将值转换为数字: {Value} | Cannot convert value to number: {Value}", value); + return value.ToString(); + } + + var culture = GetCultureInfo(); + return number.ToString($"N{decimals}", culture); + } + + private string FormatPercent(object value) + { + if (value == null) return string.Empty; + + if (!TryConvertToDouble(value, out var number)) + { + _logger.Warn("无法将值转换为百分比: {Value} | Cannot convert value to percentage: {Value}", value); + return value.ToString(); + } + + // 值在 0-1 范围内视为小数百分比 | Values in 0-1 range treated as decimal percentage + if (number >= 0 && number <= 1) + { + number *= 100; + } + + var culture = GetCultureInfo(); + return number.ToString("F2", culture) + "%"; + } + + + private bool TryConvertToDouble(object value, out double result) + { + result = 0; + if (value == null) return false; + + switch (value) + { + case double d: result = d; return true; + case float f: result = f; return true; + case int i: result = i; return true; + case long l: result = l; return true; + case decimal dec: result = (double)dec; return true; + default: + return double.TryParse(value.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out result); + } + } + + private CultureInfo GetCultureInfo() + { + return _localizationService.CurrentLanguage switch + { + SupportedLanguage.ZhCN => new CultureInfo("zh-CN"), + SupportedLanguage.ZhTW => new CultureInfo("zh-TW"), + SupportedLanguage.EnUS => new CultureInfo("en-US"), + _ => CultureInfo.InvariantCulture + }; + } + + private string ConvertToString(object value) + { + if (value == null) return string.Empty; + if (value is DateTime dt) return FormatDate(dt); + return value.ToString(); + } + + private ReportTemplate DeepClone(ReportTemplate template) + { + var json = JsonConvert.SerializeObject(template); + return JsonConvert.DeserializeObject(json); + } + } +} diff --git a/XP.ReportEngine/Services/ITextPdfRenderer.cs b/XP.ReportEngine/Services/ITextPdfRenderer.cs new file mode 100644 index 0000000..f97f21a --- /dev/null +++ b/XP.ReportEngine/Services/ITextPdfRenderer.cs @@ -0,0 +1,1481 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Windows.Media.Imaging; +using iText.IO.Font; +using iText.Kernel.Colors; +using iText.Kernel.Font; +using iText.Kernel.Geom; +using iText.Kernel.Pdf; +using iText.Kernel.Pdf.Canvas.Draw; +using iText.Layout; +using iText.Layout.Borders; +using iText.Layout.Element; +using iText.Layout.Properties; +using XP.Common.Localization.Enums; +using XP.Common.Localization.Interfaces; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Services +{ + /// + /// iText 7 PDF 渲染器实现 | iText 7 PDF renderer implementation + /// + public class ITextPdfRenderer : IPdfRenderer + { + private readonly ILoggerService _logger; + private readonly ILocalizationService _localizationService; + + /// + /// mm 到 points 的转换系数 | mm to points conversion factor + /// + private const float MmToPoints = 2.83465f; + + /// + /// A4 页面宽度(mm)| A4 page width in mm + /// + private const float A4WidthMm = 210f; + + /// + /// A4 页面高度(mm)| A4 page height in mm + /// + private const float A4HeightMm = 297f; + + /// + /// 表头背景色 | Table header background color + /// + private const string HeaderBackgroundColor = "#E0E0E0"; + + /// + /// 表格奇数行背景色 | Table odd row background color + /// + private const string OddRowBackgroundColor = "#FFFFFF"; + + /// + /// 表格偶数行背景色 | Table even row background color + /// + private const string EvenRowBackgroundColor = "#F5F5F5"; + + private PdfFont _cjkFont; + private PdfFont _westernFont; + private bool _fontsInitialized; + private readonly object _fontLock = new(); + private ReportTemplate _currentTemplate; + + public ITextPdfRenderer(ILoggerService logger, ILocalizationService localizationService) + { + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); + // 字体延迟加载,不在构造函数中阻塞 | Fonts loaded lazily, not blocking in constructor + } + + #region 7.1 基础 PDF 文档创建 | Basic PDF document creation + + /// + /// 将排版结果渲染为 PDF 内存流 | Render layout result to PDF memory stream + /// + /// 排版后的页面列表 | Laid-out pages + /// 生成选项 | Generation options + /// 绑定后的模板(用于页眉页脚配置)| Bound template (for header/footer config) + /// PDF 内存流 | PDF memory stream + public MemoryStream Render(List pages, ReportGenerationOptions options, ReportTemplate template = null) + { + _logger.Info("开始 PDF 渲染,共 {PageCount} 页 | Starting PDF rendering, {PageCount} pages", pages?.Count ?? 0); + _currentTemplate = template; + + // 每次渲染重置字体,避免跨 PdfDocument 复用导致 "belongs to other PDF document" 错误 + // Reset fonts on each render to avoid cross-PdfDocument reuse error + _fontsInitialized = false; + _cjkFont = null; + _westernFont = null; + + var memoryStream = new MemoryStream(); + + try + { + var writer = new PdfWriter(memoryStream, new WriterProperties().SetFullCompressionMode(true)); + // 防止 PdfWriter 关闭时关闭底层流 | Prevent PdfWriter from closing the underlying stream + writer.SetCloseStream(false); + + var pdfDocument = new PdfDocument(writer); + // 设置 A4 页面尺寸 | Set A4 page size + pdfDocument.SetDefaultPageSize(PageSize.A4); + + var document = new Document(pdfDocument); + + // 设置默认边距(使用默认 20mm)| Set default margins (20mm default) + float marginTop = 20f * MmToPoints; + float marginBottom = 20f * MmToPoints; + float marginLeft = 20f * MmToPoints; + float marginRight = 20f * MmToPoints; + + // 如果有页眉页脚配置,为内容页增加边距空间 | Increase margins for header/footer on content pages + var headerConfig = template?.Document?.Header; + var footerConfig = template?.Document?.Footer; + bool hasHeader = headerConfig != null && headerConfig.Enabled; + bool hasFooter = footerConfig != null && footerConfig.Enabled; + + // 页眉页脚占用的额外空间(mm → points)| Extra space for header/footer + float headerAreaHeight = hasHeader ? 15f * MmToPoints : 0f; + float footerAreaHeight = hasFooter ? 12f * MmToPoints : 0f; + + document.SetMargins(marginTop, marginRight, marginBottom, marginLeft); + + // 注册页眉页脚事件处理器 | Register header/footer event handler + HeaderFooterEventHandler headerFooterHandler = null; + if (hasHeader || hasFooter) + { + headerFooterHandler = new HeaderFooterEventHandler( + this, template, pages, _logger); + pdfDocument.AddEventHandler(iText.Kernel.Events.PdfDocumentEvent.END_PAGE, headerFooterHandler); + } + + if (pages != null && pages.Count > 0) + { + for (int i = 0; i < pages.Count; i++) + { + var pageStopwatch = System.Diagnostics.Stopwatch.StartNew(); + + if (i > 0) + { + // 添加新页面 | Add new page + document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE)); + } + + // 非首页增加页眉页脚边距 | Add header/footer margins for non-homepage + bool isHomepage = string.Equals(pages[i].PageType, "homepage", StringComparison.OrdinalIgnoreCase); + if (!isHomepage) + { + // 通过添加顶部间距为页眉留出空间 | Add top spacing for header area + if (hasHeader) + { + document.Add(new Paragraph("").SetMarginBottom(headerAreaHeight).SetFontSize(1)); + } + } + + RenderPage(document, pages[i]); + + pageStopwatch.Stop(); + _logger.Info("第 {PageIndex}/{TotalPages} 页渲染完成,类型: {PageType},元素数: {ElementCount},耗时: {ElapsedMs}ms | Page {PageIndex}/{TotalPages} rendered, type: {PageType}, elements: {ElementCount}, elapsed: {ElapsedMs}ms", + i + 1, pages.Count, pages[i].PageType ?? "unknown", pages[i].Elements?.Count ?? 0, pageStopwatch.ElapsedMilliseconds); + } + } + + // 文档关闭前回填总页数占位符 | Fill total page count placeholder before closing + if (headerFooterHandler != null) + { + headerFooterHandler.WriteTotal(pdfDocument); + } + + // 关闭文档(触发字体子集化嵌入 + PDF 交叉引用表写入 + 流压缩) + // Close document (triggers font subsetting + PDF cross-reference table writing + stream compression) + _logger.Info("开始关闭文档(字体嵌入 + 压缩)| Starting document close (font embedding + compression)"); + var closeStopwatch = System.Diagnostics.Stopwatch.StartNew(); + document.Close(); + closeStopwatch.Stop(); + _logger.Info("文档关闭完成,耗时: {ElapsedMs}ms | Document close completed, elapsed: {ElapsedMs}ms", closeStopwatch.ElapsedMilliseconds); + + // 重置流位置以便后续读取 | Reset stream position for subsequent reading + memoryStream.Position = 0; + _logger.Info("PDF 渲染完成 | PDF rendering completed"); + } + catch (Exception ex) + { + _logger.Error(ex, "PDF 渲染过程中发生错误 | Error occurred during PDF rendering: {Message}", ex.Message); + throw; + } + + return memoryStream; + } + + /// + /// 渲染单个页面 | Render a single page + /// + private void RenderPage(Document document, LayoutPage page) + { + if (page?.Elements == null) return; + + foreach (var element in page.Elements) + { + try + { + RenderElement(document, element); + } + catch (Exception ex) + { + _logger.Warn("渲染元素失败,跳过该元素 | Failed to render element, skipping: {Message}", ex.Message); + } + } + } + + /// + /// 根据元素类型分发渲染 | Dispatch rendering based on element type + /// + private void RenderElement(Document document, LayoutElement element) + { + if (element?.Source == null) return; + + var elementType = element.Source.Type?.ToLowerInvariant(); + + switch (elementType) + { + case "text": + RenderTextElement(document, element); + break; + case "image": + RenderImageElement(document, element); + break; + case "table": + RenderTableElement(document, element); + break; + case "divider": + RenderDividerElement(document, element); + break; + case "spacer": + RenderSpacerElement(document, element); + break; + case "row": + RenderRowElement(document, element); + break; + case "pagebreak": + RenderPageBreakElement(document); + break; + default: + _logger.Warn("未知的元素类型:{Type},跳过渲染 | Unknown element type: {Type}, skipping", elementType); + break; + } + } + + #endregion + + #region 7.2 文本元素渲染 | Text element rendering + + /// + /// 渲染文本元素 | Render text element + /// + private void RenderTextElement(Document document, LayoutElement element) + { + var content = element.ResolvedContent ?? string.Empty; + var style = element.ResolvedStyle ?? new StyleDefinition(); + + var paragraph = new Paragraph(content); + + // 设置紧凑的默认段落间距 | Set compact default paragraph spacing + paragraph.SetMarginTop(0); + paragraph.SetMarginBottom(2f); + + // 应用字体 | Apply font + var font = GetFontForCurrentLanguage(); + paragraph.SetFont(font); + + // 应用字体大小 | Apply font size + paragraph.SetFontSize(style.Size); + + // 应用粗体 | Apply bold + if (style.Bold) + { + paragraph.SetBold(); + } + + // 应用斜体 | Apply italic + if (style.Italic) + { + paragraph.SetItalic(); + } + + // 应用字体颜色 | Apply font color + var color = ParseColor(style.Color); + if (color != null) + { + paragraph.SetFontColor(color); + } + + // 应用条件颜色规则(根据内容关键词覆盖颜色)| Apply conditional color rules (override color by content keywords) + if (element.Source?.ColorRules != null && !string.IsNullOrEmpty(content)) + { + foreach (var rule in element.Source.ColorRules) + { + if (content.Contains(rule.Key, StringComparison.OrdinalIgnoreCase)) + { + var ruleColor = ParseColor(rule.Value); + if (ruleColor != null) + { + paragraph.SetFontColor(ruleColor); + paragraph.SetBold(); + } + break; + } + } + } + + // 应用对齐方式 | Apply text alignment + paragraph.SetTextAlignment(ParseTextAlignment(style.Align)); + + // 应用背景色 | Apply background color + if (!string.IsNullOrEmpty(style.BackgroundColor)) + { + var bgColor = ParseColor(style.BackgroundColor); + if (bgColor != null) + { + paragraph.SetBackgroundColor(bgColor); + } + } + + // 设置固定位置(如果有坐标信息)| Set fixed position if coordinates available + if (element.Width > 0) + { + paragraph.SetWidth(element.Width * MmToPoints); + } + + // 应用边距和缩进 | Apply margins and indent + if (style.MarginTop > 0) + paragraph.SetMarginTop(style.MarginTop * MmToPoints); + if (style.MarginBottom > 0) + paragraph.SetMarginBottom(style.MarginBottom * MmToPoints); + if (style.PaddingLeft > 0) + paragraph.SetPaddingLeft(style.PaddingLeft * MmToPoints); + if (style.LineHeight > 0) + paragraph.SetMultipliedLeading(style.LineHeight); + + document.Add(paragraph); + } + + #endregion + + #region 7.3 字体管理 | Font management + + /// + /// 确保字体已初始化(线程安全的延迟加载)| Ensure fonts are initialized (thread-safe lazy loading) + /// + private void EnsureFontsInitialized() + { + if (_fontsInitialized) return; + lock (_fontLock) + { + if (_fontsInitialized) return; + InitializeFonts(); + _fontsInitialized = true; + } + } + + /// + /// 初始化字体(从系统字体目录加载)| Initialize fonts (load from system fonts directory) + /// 使用 Windows 系统自带字体,确保 Telerik RadPdfViewer 兼容性 + /// Uses Windows built-in fonts to ensure Telerik RadPdfViewer compatibility + /// + private void InitializeFonts() + { + var fontsDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Fonts"); + + // 加载微软雅黑(支持简体中文、繁体中文)| Load Microsoft YaHei (supports Simplified & Traditional Chinese) + try + { + var msyhPath = System.IO.Path.Combine(fontsDir, "msyh.ttc"); + _cjkFont = PdfFontFactory.CreateFont(msyhPath + ",0", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED); + _logger.Info("中文字体加载成功(微软雅黑)| Chinese font loaded successfully (Microsoft YaHei)"); + } + catch (Exception ex) + { + _logger.Warn("微软雅黑加载失败,尝试后备字体 | Microsoft YaHei load failed, trying fallback: {Message}", ex.Message); + try + { + // 后备:宋体 | Fallback: SimSun + var simsunPath = System.IO.Path.Combine(fontsDir, "simsun.ttc"); + _cjkFont = PdfFontFactory.CreateFont(simsunPath + ",0", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED); + _logger.Info("中文后备字体加载成功(宋体)| Chinese fallback font loaded successfully (SimSun)"); + } + catch (Exception ex2) + { + _logger.Warn("宋体加载失败 | SimSun load failed: {Message}", ex2.Message); + _cjkFont = null; + } + } + + // 加载 Arial(西文字体)| Load Arial (Western font) + try + { + var arialPath = System.IO.Path.Combine(fontsDir, "arial.ttf"); + _westernFont = PdfFontFactory.CreateFont(arialPath, PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED); + _logger.Info("西文字体加载成功(Arial)| Western font loaded successfully (Arial)"); + } + catch (Exception ex) + { + _logger.Warn("Arial 加载失败,使用 Helvetica 后备 | Arial load failed, using Helvetica fallback: {Message}", ex.Message); + _westernFont = null; + } + + // 如果系统字体都不可用,使用 iText 内置 Helvetica | If system fonts unavailable, use built-in Helvetica + if (_cjkFont == null && _westernFont == null) + { + _logger.Warn("所有系统字体不可用,使用 Helvetica 后备字体 | All system fonts unavailable, using Helvetica fallback"); + } + } + + /// + /// 根据当前语言获取合适的字体 | Get appropriate font based on current language + /// zh-CN / zh-TW → 微软雅黑(支持简繁体);en-US → Arial + /// + /// PDF 字体 | PDF font + private PdfFont GetFontForCurrentLanguage() + { + // 延迟初始化字体 | Lazy initialize fonts + EnsureFontsInitialized(); + + var language = _localizationService.CurrentLanguage; + + PdfFont selectedFont; + switch (language) + { + case SupportedLanguage.ZhCN: + case SupportedLanguage.ZhTW: + selectedFont = _cjkFont; + break; + case SupportedLanguage.EnUS: + default: + selectedFont = _westernFont ?? _cjkFont; // 西文优先,中文后备(微软雅黑也支持西文)| Western preferred, CJK fallback (YaHei supports Western too) + break; + } + + // 后备字体逻辑 | Fallback font logic + if (selectedFont != null) + { + return selectedFont; + } + + // 尝试使用其他字体 | Try other fonts + if (_cjkFont != null) return _cjkFont; + if (_westernFont != null) return _westernFont; + + // 最终后备:使用 iText 内置 Helvetica | Final fallback: use built-in Helvetica + return PdfFontFactory.CreateFont(iText.IO.Font.Constants.StandardFonts.HELVETICA); + } + + #endregion + + #region 7.4 图像嵌入渲染 | Image embedding rendering + + /// + /// 渲染图像元素 | Render image element + /// + private void RenderImageElement(Document document, LayoutElement element) + { + var imageData = element.ResolvedImage; + + // 如果图像数据缺失,渲染占位矩形 | If image data is missing, render placeholder + if (imageData == null) + { + _logger.Warn("图像数据为空,渲染占位矩形 | Image data is null, rendering placeholder"); + RenderImagePlaceholder(document, element); + return; + } + + try + { + byte[] imageBytes = GetImageBytes(imageData); + + if (imageBytes == null || imageBytes.Length == 0) + { + _logger.Warn("图像字节数据为空,渲染占位矩形 | Image byte data is empty, rendering placeholder"); + RenderImagePlaceholder(document, element); + return; + } + + // 创建 iText 图像对象 | Create iText image object + var iTextImageData = iText.IO.Image.ImageDataFactory.Create(imageBytes); + var image = new Image(iTextImageData); + + // 计算目标区域尺寸(mm → points)| Calculate target area size (mm → points) + float targetWidthPt = element.Width * MmToPoints; + float targetHeightPt = element.Height * MmToPoints; + + // 等比缩放以适应目标区域 | Scale proportionally to fit target area + if (targetWidthPt > 0 && targetHeightPt > 0) + { + float imageWidth = image.GetImageWidth(); + float imageHeight = image.GetImageHeight(); + + float scaleX = targetWidthPt / imageWidth; + float scaleY = targetHeightPt / imageHeight; + float scale = Math.Min(scaleX, scaleY); + + image.SetWidth(imageWidth * scale); + image.SetHeight(imageHeight * scale); + } + else if (targetWidthPt > 0) + { + image.SetWidth(targetWidthPt); + image.ScaleToFit(targetWidthPt, float.MaxValue); + } + + // 应用边框 | Apply border + if (element.Source?.Border == true) + { + image.SetBorder(new SolidBorder(ColorConstants.BLACK, 1f)); + } + + // 应用对齐方式 | Apply alignment + var align = element.Source?.Align?.ToLowerInvariant(); + if (align == "center") + { + image.SetHorizontalAlignment(HorizontalAlignment.CENTER); + } + else if (align == "right") + { + image.SetHorizontalAlignment(HorizontalAlignment.RIGHT); + } + + // 应用样式中的边距 | Apply margins from style + var style = element.ResolvedStyle; + if (style != null) + { + if (style.MarginTop > 0) + image.SetMarginTop(style.MarginTop * MmToPoints); + if (style.MarginBottom > 0) + image.SetMarginBottom(style.MarginBottom * MmToPoints); + } + + document.Add(image); + } + catch (Exception ex) + { + _logger.Warn("图像渲染失败,渲染占位矩形 | Image rendering failed, rendering placeholder: {Message}", ex.Message); + RenderImagePlaceholder(document, element); + } + } + + /// + /// 从 ImageData 获取字节数组 | Get byte array from ImageData + /// + private byte[] GetImageBytes(ImageData imageData) + { + switch (imageData.SourceType) + { + case ImageSourceType.Bytes: + return imageData.Bytes; + + case ImageSourceType.FilePath: + if (!string.IsNullOrEmpty(imageData.FilePath) && File.Exists(imageData.FilePath)) + { + return File.ReadAllBytes(imageData.FilePath); + } + _logger.Warn("图像文件不存在:{Path} | Image file not found: {Path}", imageData.FilePath); + return null; + + case ImageSourceType.BitmapSource: + if (imageData.BitmapSource is BitmapSource bitmapSource) + { + return ConvertBitmapSourceToBytes(bitmapSource); + } + _logger.Warn("BitmapSource 对象无效 | BitmapSource object is invalid"); + return null; + + default: + _logger.Warn("未知的图像来源类型:{Type} | Unknown image source type: {Type}", imageData.SourceType); + return null; + } + } + + #endregion + + #region 7.5 BitmapSource 转 byte[] | BitmapSource to byte[] conversion + + /// + /// 将 BitmapSource 转换为 PNG 编码的字节数组 | Convert BitmapSource to PNG-encoded byte array + /// + /// WPF BitmapSource 对象 | WPF BitmapSource object + /// PNG 编码的字节数组 | PNG-encoded byte array + public static byte[] ConvertBitmapSourceToBytes(BitmapSource bitmapSource) + { + if (bitmapSource == null) + { + return null; + } + + using (var memoryStream = new MemoryStream()) + { + var encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); + encoder.Save(memoryStream); + return memoryStream.ToArray(); + } + } + + #endregion + + #region 7.6 图像占位矩形渲染 | Image placeholder rendering + + /// + /// 渲染图像缺失时的占位矩形(带"无图像 | No Image"文本标签) + /// Render placeholder rectangle when image is missing (with "无图像 | No Image" text label) + /// + private void RenderImagePlaceholder(Document document, LayoutElement element) + { + float widthPt = element.Width > 0 ? element.Width * MmToPoints : 100f * MmToPoints; + float heightPt = element.Height > 0 ? element.Height * MmToPoints : 60f * MmToPoints; + + // 使用表格模拟占位矩形(带边框和居中文本)| Use table to simulate placeholder rectangle + var table = new Table(1); + table.SetWidth(widthPt); + + var cell = new Cell(); + cell.SetHeight(heightPt); + cell.SetBorder(new SolidBorder(ColorConstants.GRAY, 1f)); + cell.SetBackgroundColor(new DeviceRgb(245, 245, 245)); + + // 居中显示"无图像 | No Image"文本 | Center "无图像 | No Image" text + var placeholderText = new Paragraph("无图像 | No Image"); + var font = GetFontForCurrentLanguage(); + placeholderText.SetFont(font); + placeholderText.SetFontSize(10f); + placeholderText.SetFontColor(ColorConstants.GRAY); + placeholderText.SetTextAlignment(TextAlignment.CENTER); + + cell.SetVerticalAlignment(VerticalAlignment.MIDDLE); + cell.Add(placeholderText); + table.AddCell(cell); + + document.Add(table); + } + + #endregion + + #region 7.7 表格渲染 | Table rendering + + /// + /// 渲染表格元素 | Render table element + /// + private void RenderTableElement(Document document, LayoutElement element) + { + var columns = element.Source?.Columns; + var tableData = element.ResolvedTableData; + + if (columns == null || columns.Count == 0) + { + _logger.Warn("表格列定义为空,跳过渲染 | Table column definitions are empty, skipping"); + return; + } + + // 计算列宽(mm → points)| Calculate column widths (mm → points) + var columnWidths = new float[columns.Count]; + for (int i = 0; i < columns.Count; i++) + { + columnWidths[i] = columns[i].Width > 0 ? columns[i].Width * MmToPoints : 30f * MmToPoints; + } + + var table = new Table(columnWidths); + table.SetWidth(UnitValue.CreatePercentValue(100)); + + var font = GetFontForCurrentLanguage(); + + // 渲染表头行 | Render header row + var headerBgColor = ParseColor(HeaderBackgroundColor); + foreach (var column in columns) + { + var headerCell = new Cell(); + var headerParagraph = new Paragraph(column.Header ?? string.Empty); + headerParagraph.SetFont(font); + headerParagraph.SetFontSize(10f); + headerParagraph.SetBold(); + headerParagraph.SetTextAlignment(ParseTextAlignment(column.Align)); + + headerCell.Add(headerParagraph); + headerCell.SetBackgroundColor(headerBgColor); + headerCell.SetBorder(new SolidBorder(ColorConstants.LIGHT_GRAY, 0.5f)); + + table.AddHeaderCell(headerCell); + } + + // 渲染数据行(交替背景色)| Render data rows (alternating background colors) + if (tableData != null) + { + for (int rowIndex = 0; rowIndex < tableData.Count; rowIndex++) + { + var rowData = tableData[rowIndex]; + var rowBgColor = rowIndex % 2 == 0 + ? ParseColor(OddRowBackgroundColor) + : ParseColor(EvenRowBackgroundColor); + + foreach (var column in columns) + { + var dataCell = new Cell(); + + // 从行数据中获取字段值 | Get field value from row data + string cellValue = string.Empty; + if (rowData != null && !string.IsNullOrEmpty(column.Field) && rowData.ContainsKey(column.Field)) + { + cellValue = rowData[column.Field]?.ToString() ?? string.Empty; + } + + var cellParagraph = new Paragraph(cellValue); + cellParagraph.SetFont(font); + cellParagraph.SetFontSize(9f); + cellParagraph.SetTextAlignment(ParseTextAlignment(column.Align)); + + // 应用条件颜色规则 | Apply conditional color rules + if (column.ColorRules != null && !string.IsNullOrEmpty(cellValue)) + { + foreach (var rule in column.ColorRules) + { + if (string.Equals(cellValue, rule.Key, StringComparison.OrdinalIgnoreCase) + || cellValue.Contains(rule.Key, StringComparison.OrdinalIgnoreCase)) + { + var ruleColor = ParseColor(rule.Value); + if (ruleColor != null) + { + cellParagraph.SetFontColor(ruleColor); + cellParagraph.SetBold(); + } + break; + } + } + } + + dataCell.Add(cellParagraph); + dataCell.SetBackgroundColor(rowBgColor); + dataCell.SetBorder(new SolidBorder(ColorConstants.LIGHT_GRAY, 0.5f)); + + table.AddCell(dataCell); + } + } + } + + // 应用样式中的边距 | Apply margins from style + var style = element.ResolvedStyle; + if (style != null) + { + if (style.MarginTop > 0) + table.SetMarginTop(style.MarginTop * MmToPoints); + if (style.MarginBottom > 0) + table.SetMarginBottom(style.MarginBottom * MmToPoints); + } + + document.Add(table); + } + + #endregion + + #region 7.8 分隔线渲染 | Divider rendering + + /// + /// 渲染分隔线元素 | Render divider element + /// + private void RenderDividerElement(Document document, LayoutElement element) + { + var style = element.ResolvedStyle; + + // 确定分隔线颜色(从样式或默认灰色)| Determine divider color (from style or default gray) + Color lineColor = ColorConstants.GRAY; + if (style != null && !string.IsNullOrEmpty(style.Color)) + { + var parsedColor = ParseColor(style.Color); + if (parsedColor != null) + { + lineColor = parsedColor; + } + } + + // 使用 LineSeparator 渲染水平分隔线 | Use LineSeparator to render horizontal divider + var lineSeparator = new LineSeparator(new SolidLine(1f)); + lineSeparator.SetStrokeColor(lineColor); + + // 设置宽度为可用区域全宽 | Set width to full available area + if (element.Width > 0) + { + lineSeparator.SetWidth(element.Width * MmToPoints); + } + + // 添加上下间距 | Add vertical spacing + lineSeparator.SetMarginTop(5f); + lineSeparator.SetMarginBottom(5f); + + document.Add(lineSeparator); + } + + /// + /// 渲染空白间距元素 | Render spacer element + /// 通过 Size[1](高度,mm)控制垂直空白大小 + /// Controls vertical whitespace via Size[1] (height in mm) + /// + private void RenderSpacerElement(Document document, LayoutElement element) + { + // 从 Size[1] 获取高度,默认 10mm | Get height from Size[1], default 10mm + float heightMm = 10f; + if (element.Source?.Size is { Length: >= 2 }) + { + heightMm = element.Source.Size[1]; + } + + // 使用空段落撑出指定高度的空白 | Use empty paragraph to create specified height whitespace + var spacer = new Paragraph("") + .SetFontSize(1) + .SetMarginTop(0) + .SetMarginBottom(heightMm * MmToPoints); + + document.Add(spacer); + } + + /// + /// 渲染强制分页元素 | Render forced page break element + /// + private void RenderPageBreakElement(Document document) + { + document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE)); + } + + /// + /// 渲染行容器元素(水平布局)| Render row container element (horizontal layout) + /// 使用无边框表格实现子元素的水平排列,支持 left/center/right 对齐 + /// Uses borderless table to arrange child elements horizontally, supports left/center/right alignment + /// + private void RenderRowElement(Document document, LayoutElement element) + { + var children = element.Source?.Children; + if (children == null || children.Count == 0) return; + + // 创建表格,支持自定义列宽比例 | Create table with custom column width ratios + var columnCount = children.Count; + Table table; + + if (element.Source.Widths != null && element.Source.Widths.Length == columnCount) + { + // 使用指定的列宽比例 | Use specified column width ratios + var totalRatio = 0f; + foreach (var w in element.Source.Widths) totalRatio += w; + + var columnWidths = new float[columnCount]; + for (int i = 0; i < columnCount; i++) + { + columnWidths[i] = element.Source.Widths[i] / totalRatio; + } + table = new Table(UnitValue.CreatePercentArray(columnWidths)); + } + else + { + // 均分列宽 | Equal column widths + table = new Table(columnCount); + } + + table.UseAllAvailableWidth(); + table.SetBorder(iText.Layout.Borders.Border.NO_BORDER); + + var font = GetFontForCurrentLanguage(); + + foreach (var child in children) + { + var cell = new Cell(); + cell.SetBorder(iText.Layout.Borders.Border.NO_BORDER); + cell.SetPadding(0); + + // 确定子元素对齐方式 | Determine child element alignment + var align = child.Align?.ToLowerInvariant() ?? "left"; + cell.SetTextAlignment(ParseTextAlignment(align)); + + var childType = child.Type?.ToLowerInvariant(); + + if (childType == "column") + { + // 渲染列容器子元素(垂直堆叠多个元素在同一单元格内) + // Render column container child (stack multiple elements vertically in same cell) + if (child.Children != null) + { + foreach (var subChild in child.Children) + { + RenderRowChildIntoCell(cell, subChild, align, font); + } + } + } + else + { + RenderRowChildIntoCell(cell, child, align, font); + } + + table.AddCell(cell); + } + + document.Add(table); + } + + /// + /// 将单个子元素渲染到单元格中 | Render a single child element into a cell + /// + private void RenderRowChildIntoCell(Cell cell, TemplateElement child, string align, PdfFont font) + { + var childType = child.Type?.ToLowerInvariant(); + // 子元素可以覆盖父级对齐 | Child can override parent alignment + var childAlign = child.Align?.ToLowerInvariant() ?? align; + + if (childType == "image") + { + // 渲染图像子元素 | Render image child element + var imageData = child.ImageData; + if (imageData != null) + { + try + { + byte[] imageBytes = GetImageBytes(imageData); + if (imageBytes != null && imageBytes.Length > 0) + { + var iTextImageData = iText.IO.Image.ImageDataFactory.Create(imageBytes); + var image = new Image(iTextImageData); + + // 应用尺寸 | Apply size + float targetWidthPt = child.Size != null && child.Size.Length > 0 ? child.Size[0] * MmToPoints : 0; + float targetHeightPt = child.Size != null && child.Size.Length > 1 ? child.Size[1] * MmToPoints : 0; + + if (targetWidthPt > 0 && targetHeightPt > 0) + { + float imageWidth = image.GetImageWidth(); + float imageHeight = image.GetImageHeight(); + float scaleX = targetWidthPt / imageWidth; + float scaleY = targetHeightPt / imageHeight; + float scale = Math.Min(scaleX, scaleY); + image.SetWidth(imageWidth * scale); + image.SetHeight(imageHeight * scale); + } + + // 设置图像水平对齐 | Set image horizontal alignment + if (childAlign == "right") + image.SetHorizontalAlignment(HorizontalAlignment.RIGHT); + else if (childAlign == "center") + image.SetHorizontalAlignment(HorizontalAlignment.CENTER); + else + image.SetHorizontalAlignment(HorizontalAlignment.LEFT); + + cell.Add(image); + } + } + catch (Exception ex) + { + _logger.Warn("Row 子元素图像渲染失败 | Row child image rendering failed: {Message}", ex.Message); + } + } + } + else if (childType == "text") + { + // 渲染文本子元素 | Render text child element + var content = child.Content ?? string.Empty; + var style = ResolveStyleFromTemplate(child.Style); + + var paragraph = new Paragraph(content); + paragraph.SetFont(font); + paragraph.SetFontSize(style.Size); + if (style.Bold) paragraph.SetBold(); + if (style.Italic) paragraph.SetItalic(); + + var color = ParseColor(style.Color); + if (color != null) paragraph.SetFontColor(color); + + // 应用条件颜色规则 | Apply conditional color rules + if (child.ColorRules != null && !string.IsNullOrEmpty(content)) + { + foreach (var rule in child.ColorRules) + { + if (content.Contains(rule.Key, StringComparison.OrdinalIgnoreCase)) + { + var ruleColor = ParseColor(rule.Value); + if (ruleColor != null) + { + paragraph.SetFontColor(ruleColor); + paragraph.SetBold(); + } + break; + } + } + } + + paragraph.SetTextAlignment(ParseTextAlignment(childAlign)); + paragraph.SetMargin(0); + + cell.Add(paragraph); + } + } + + /// + /// 从当前模板中解析样式定义 | Resolve style definition from current template + /// + private StyleDefinition ResolveStyleFromTemplate(string styleName) + { + if (string.IsNullOrWhiteSpace(styleName)) + return new StyleDefinition(); + + if (_currentTemplate?.Styles != null + && _currentTemplate.Styles.TryGetValue(styleName, out var style)) + { + return style; + } + + return new StyleDefinition(); + } + + #endregion + + #region 7.85 页眉页脚渲染(事件驱动)| Header/Footer rendering (event-driven) + + /// + /// 页眉页脚事件处理器 | Header/Footer event handler + /// 在 END_PAGE 事件中绘制页眉页脚,使用 PdfFormXObject 占位符实现总页数回填 + /// Draws header/footer in END_PAGE event, uses PdfFormXObject placeholder for total page count + /// + private class HeaderFooterEventHandler : iText.Kernel.Events.IEventHandler + { + private readonly ITextPdfRenderer _renderer; + private readonly ReportTemplate _template; + private readonly List _pages; + private readonly ILoggerService _logger; + private readonly HeaderFooterSettings _headerConfig; + private readonly HeaderFooterSettings _footerConfig; + private readonly MarginSettings _margins; + private readonly PdfFont _font; + + // 首页数量 | Homepage count + private readonly int _homepageCount; + + // 总页数占位符模板(用于回填)| Total page count placeholder template (for backfill) + private readonly iText.Kernel.Pdf.Xobject.PdfFormXObject _totalPagePlaceholder; + private readonly List<(iText.Kernel.Pdf.Canvas.PdfCanvas canvas, float x, float y)> _totalPagePositions = new(); + + // 当前页面索引(从 0 开始)| Current page index (0-based) + private int _currentPageIndex = -1; + + public HeaderFooterEventHandler( + ITextPdfRenderer renderer, + ReportTemplate template, + List pages, + ILoggerService logger) + { + _renderer = renderer; + _template = template; + _pages = pages; + _logger = logger; + _headerConfig = template?.Document?.Header; + _footerConfig = template?.Document?.Footer; + _margins = template?.Document?.Margins ?? new MarginSettings(); + _font = renderer.GetFontForCurrentLanguage(); + + // 计算首页数量 | Calculate homepage count + _homepageCount = 0; + if (pages != null) + { + for (int i = 0; i < pages.Count; i++) + { + if (string.Equals(pages[i].PageType, "homepage", StringComparison.OrdinalIgnoreCase)) + _homepageCount++; + else + break; + } + } + + // 创建总页数占位符(固定宽度区域)| Create total page count placeholder (fixed width area) + _totalPagePlaceholder = new iText.Kernel.Pdf.Xobject.PdfFormXObject(new Rectangle(0, 0, 30, 12)); + } + + public void HandleEvent(iText.Kernel.Events.Event @event) + { + if (@event is not iText.Kernel.Events.PdfDocumentEvent docEvent) return; + + _currentPageIndex++; + var pdfDoc = docEvent.GetDocument(); + var pdfPage = docEvent.GetPage(); + var pageSize = pdfPage.GetPageSize(); + + // 跳过首页 | Skip homepage + if (_currentPageIndex < _homepageCount) return; + + int currentContentPageNum = _currentPageIndex - _homepageCount + 1; + + try + { + var canvas = new iText.Kernel.Pdf.Canvas.PdfCanvas(pdfPage.NewContentStreamBefore(), pdfPage.GetResources(), pdfDoc); + + // 绘制页眉 | Draw header + if (_headerConfig != null && _headerConfig.Enabled) + { + DrawHeader(canvas, pageSize); + } + + // 绘制页脚 | Draw footer + if (_footerConfig != null && _footerConfig.Enabled) + { + DrawFooter(canvas, pageSize, pdfDoc, currentContentPageNum); + } + + canvas.Release(); + } + catch (Exception ex) + { + _logger.Warn("页眉页脚绘制异常 | Header/footer drawing exception: {Message}", ex.Message); + } + } + + /// + /// 绘制页眉 | Draw header + /// + private void DrawHeader(iText.Kernel.Pdf.Canvas.PdfCanvas canvas, Rectangle pageSize) + { + float leftX = _margins.Left * MmToPoints; + float rightX = pageSize.GetWidth() - _margins.Right * MmToPoints; + float topY = pageSize.GetHeight() - (_margins.Top * MmToPoints * 0.3f); + + float fontSize = _headerConfig.FontSize > 0 ? _headerConfig.FontSize : 8f; + var fontColor = _renderer.ParseColor(_headerConfig.Color ?? "#666666"); + + // 绘制左侧文本行 | Draw left-side text lines + if (_headerConfig.Left != null && _headerConfig.Left.Count > 0) + { + float lineY = topY; + float lineSpacing = (fontSize + 2f) * 1.2f; + + foreach (var line in _headerConfig.Left) + { + if (string.IsNullOrEmpty(line)) continue; + + canvas.BeginText() + .SetFontAndSize(_font, fontSize) + .MoveText(leftX, lineY) + .ShowText(line) + .EndText(); + + lineY -= lineSpacing; + } + } + + // 绘制右上角 Logo | Draw right-side logo + if (!string.IsNullOrEmpty(_headerConfig.RightImageKey)) + { + try + { + ImageData logoImageData = _renderer.FindBoundImage(_template, _headerConfig.RightImageKey); + if (logoImageData != null) + { + byte[] imageBytes = _renderer.GetImageBytes(logoImageData); + if (imageBytes != null && imageBytes.Length > 0) + { + var iTextImageData = iText.IO.Image.ImageDataFactory.Create(imageBytes); + float logoHeight = 10f * MmToPoints; + float logoWidth = logoHeight * (iTextImageData.GetWidth() / iTextImageData.GetHeight()); + + float logoX = rightX - logoWidth; + float logoY = topY - logoHeight + fontSize; + + canvas.AddImageFittedIntoRectangle(iTextImageData, + new Rectangle(logoX, logoY, logoWidth, logoHeight), false); + } + } + } + catch (Exception ex) + { + _logger.Warn("页眉 Logo 渲染失败 | Header logo rendering failed: {Message}", ex.Message); + } + } + + // 绘制页眉分隔线 | Draw header separator line + if (_headerConfig.ShowLine) + { + float lineY = topY - (_headerConfig.Left?.Count ?? 1) * ((fontSize + 2f) * 1.2f) - 3f; + canvas.SetStrokeColor(fontColor) + .SetLineWidth(0.5f) + .MoveTo(leftX, lineY) + .LineTo(rightX, lineY) + .Stroke(); + } + } + + /// + /// 绘制页脚 | Draw footer + /// + private void DrawFooter(iText.Kernel.Pdf.Canvas.PdfCanvas canvas, Rectangle pageSize, PdfDocument pdfDoc, int currentPage) + { + float leftX = _margins.Left * MmToPoints; + float rightX = pageSize.GetWidth() - _margins.Right * MmToPoints; + float bottomY = _margins.Bottom * MmToPoints * 0.5f; + + float fontSize = _footerConfig.FontSize > 0 ? _footerConfig.FontSize : 8f; + var fontColor = _renderer.ParseColor(_footerConfig.Color ?? "#666666"); + + // 绘制页脚分隔线 | Draw footer separator line + if (_footerConfig.ShowLine) + { + float lineY = bottomY + fontSize + 5f; + canvas.SetStrokeColor(fontColor) + .SetLineWidth(0.5f) + .MoveTo(leftX, lineY) + .LineTo(rightX, lineY) + .Stroke(); + } + + // 绘制左侧文本(公司名称)| Draw left-side text (company name) + if (_footerConfig.Left != null && _footerConfig.Left.Count > 0) + { + var leftText = _footerConfig.Left[0] ?? string.Empty; + canvas.BeginText() + .SetFontAndSize(_font, fontSize) + .MoveText(leftX, bottomY) + .ShowText(leftText) + .EndText(); + } + + // 绘制右侧页码(当前页 / 总页数占位符)| Draw right-side page number (current / total placeholder) + if (_footerConfig.Right != null && _footerConfig.Right.Count > 0) + { + var pageNumTemplate = _footerConfig.Right[0] ?? string.Empty; + // 先写当前页码部分 | Write current page number part + var currentPageText = pageNumTemplate.Replace("{currentPage}", currentPage.ToString()).Replace("{totalPages}", ""); + // 分离出 totalPages 前后的文本 | Separate text around totalPages + var parts = pageNumTemplate.Split(new[] { "{totalPages}" }, StringSplitOptions.None); + + if (parts.Length == 2) + { + // 有总页数占位符:写前缀 + 当前页码 + 占位符 XObject + 后缀 + var prefix = parts[0].Replace("{currentPage}", currentPage.ToString()); + var suffix = parts[1]; + + float prefixWidth = _font.GetWidth(prefix, fontSize); + float suffixWidth = _font.GetWidth(suffix, fontSize); + float placeholderWidth = 15f; // 预留总页数宽度 | Reserve width for total pages + + float totalWidth = prefixWidth + placeholderWidth + suffixWidth; + float startX = rightX - totalWidth; + + // 写前缀文本 | Write prefix text + canvas.BeginText() + .SetFontAndSize(_font, fontSize) + .MoveText(startX, bottomY) + .ShowText(prefix) + .EndText(); + + // 添加总页数占位符 XObject | Add total page count placeholder XObject + float placeholderX = startX + prefixWidth; + canvas.AddXObjectAt(_totalPagePlaceholder, placeholderX, bottomY - 2f); + _totalPagePositions.Add((canvas, placeholderX, bottomY)); + + // 写后缀文本 | Write suffix text + if (!string.IsNullOrEmpty(suffix)) + { + canvas.BeginText() + .SetFontAndSize(_font, fontSize) + .MoveText(placeholderX + placeholderWidth, bottomY) + .ShowText(suffix) + .EndText(); + } + } + else + { + // 无总页数占位符,直接写文本 | No total pages placeholder, write text directly + var text = pageNumTemplate.Replace("{currentPage}", currentPage.ToString()); + float textWidth = _font.GetWidth(text, fontSize); + float textX = rightX - textWidth; + + canvas.BeginText() + .SetFontAndSize(_font, fontSize) + .MoveText(textX, bottomY) + .ShowText(text) + .EndText(); + } + } + } + + /// + /// 文档关闭前回填总页数到所有占位符 | Write total page count to all placeholders before document close + /// + public void WriteTotal(PdfDocument pdfDoc) + { + int totalContentPages = pdfDoc.GetNumberOfPages() - _homepageCount; + var totalText = totalContentPages.ToString(); + + // 在占位符 XObject 上绘制总页数 | Draw total page count on placeholder XObject + var canvas = new iText.Kernel.Pdf.Canvas.PdfCanvas(_totalPagePlaceholder, pdfDoc); + canvas.BeginText() + .SetFontAndSize(_font, _footerConfig?.FontSize > 0 ? _footerConfig.FontSize : 8f) + .MoveText(0, 2f) + .ShowText(totalText) + .EndText(); + canvas.Release(); + } + } + + /// + /// 从模板中查找已绑定的图像数据 | Find bound image data from template + /// + internal ImageData FindBoundImage(ReportTemplate template, string dataKey) + { + if (template?.Pages == null || string.IsNullOrEmpty(dataKey)) return null; + + foreach (var page in template.Pages) + { + if (page.Elements == null) continue; + foreach (var element in page.Elements) + { + var found = FindImageInElement(element, dataKey); + if (found != null) return found; + } + } + return null; + } + + /// + /// 递归搜索元素及其子元素中的图像数据 | Recursively search for image data in element and its children + /// + private ImageData FindImageInElement(TemplateElement element, string dataKey) + { + if (element == null) return null; + + // 检查当前元素 | Check current element + if (string.Equals(element.Type, "image", StringComparison.OrdinalIgnoreCase) + && string.Equals(element.DataKey, dataKey, StringComparison.OrdinalIgnoreCase) + && element.ImageData != null) + { + return element.ImageData; + } + + // 递归搜索子元素 | Recursively search children + if (element.Children != null) + { + foreach (var child in element.Children) + { + var found = FindImageInElement(child, dataKey); + if (found != null) return found; + } + } + + return null; + } + + #endregion + + #region 7.9 PDF 保存到文件 | PDF save to file + + /// + /// 将 PDF 内存流保存到文件 | Save PDF memory stream to file + /// + /// PDF 内存流 | PDF memory stream + /// 输出文件路径 | Output file path + /// 保存结果(成功/失败)| Save result (success/failure) + public ReportResult SaveToFile(MemoryStream pdfStream, string filePath) + { + if (pdfStream == null) + { + return ReportResult.Failure("PDF 流为空,无法保存 | PDF stream is null, cannot save"); + } + + if (string.IsNullOrWhiteSpace(filePath)) + { + return ReportResult.Failure("输出文件路径为空 | Output file path is empty"); + } + + try + { + _logger.Info("开始保存 PDF 到文件:{FilePath} | Saving PDF to file: {FilePath}", filePath); + + // 确保目标目录存在 | Ensure target directory exists + var directory = System.IO.Path.GetDirectoryName(filePath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + // 保存流位置并重置 | Save stream position and reset + long originalPosition = pdfStream.Position; + pdfStream.Position = 0; + + using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)) + { + pdfStream.CopyTo(fileStream); + } + + // 恢复流位置 | Restore stream position + pdfStream.Position = originalPosition; + + _logger.Info("PDF 文件保存成功:{FilePath} | PDF file saved successfully: {FilePath}", filePath); + return ReportResult.Success(pdfStream); + } + catch (UnauthorizedAccessException ex) + { + _logger.Error(ex, "PDF 保存失败:无写入权限 | PDF save failed: no write permission: {Path}", filePath); + return ReportResult.Failure($"无法写入文件,权限不足:{filePath} | Cannot write file, insufficient permissions: {filePath}", ex); + } + catch (DirectoryNotFoundException ex) + { + _logger.Error(ex, "PDF 保存失败:目录不存在 | PDF save failed: directory not found: {Path}", filePath); + return ReportResult.Failure($"目标目录不存在:{filePath} | Target directory not found: {filePath}", ex); + } + catch (IOException ex) + { + _logger.Error(ex, "PDF 保存失败:IO 错误 | PDF save failed: IO error: {Path}", filePath); + return ReportResult.Failure($"文件保存 IO 错误:{ex.Message} | File save IO error: {ex.Message}", ex); + } + catch (Exception ex) + { + _logger.Error(ex, "PDF 保存失败:未知错误 | PDF save failed: unknown error: {Path}", filePath); + return ReportResult.Failure($"文件保存过程中发生错误:{ex.Message} | Error occurred during file save: {ex.Message}", ex); + } + } + + #endregion + + #region 辅助方法 | Helper methods + + /// + /// 解析十六进制颜色字符串为 iText Color 对象 | Parse hex color string to iText Color object + /// 支持格式:#RRGGBB 或 #RGB | Supports formats: #RRGGBB or #RGB + /// + /// 十六进制颜色字符串 | Hex color string + /// iText Color 对象,解析失败返回黑色 | iText Color object, returns black on failure + private Color ParseColor(string hexColor) + { + if (string.IsNullOrEmpty(hexColor)) + { + return ColorConstants.BLACK; + } + + try + { + var hex = hexColor.TrimStart('#'); + + if (hex.Length == 3) + { + // 扩展 #RGB 为 #RRGGBB | Expand #RGB to #RRGGBB + hex = $"{hex[0]}{hex[0]}{hex[1]}{hex[1]}{hex[2]}{hex[2]}"; + } + + if (hex.Length == 6) + { + int r = Convert.ToInt32(hex.Substring(0, 2), 16); + int g = Convert.ToInt32(hex.Substring(2, 2), 16); + int b = Convert.ToInt32(hex.Substring(4, 2), 16); + return new DeviceRgb(r, g, b); + } + } + catch (Exception ex) + { + _logger.Warn("颜色解析失败:{Color},使用默认黑色 | Color parsing failed: {Color}, using default black: {Message}", hexColor, ex.Message); + } + + return ColorConstants.BLACK; + } + + /// + /// 解析对齐方式字符串为 iText TextAlignment | Parse alignment string to iText TextAlignment + /// + /// 对齐方式字符串(left/center/right)| Alignment string + /// iText TextAlignment 枚举值 | iText TextAlignment enum value + private TextAlignment ParseTextAlignment(string align) + { + switch (align?.ToLowerInvariant()) + { + case "center": + return TextAlignment.CENTER; + case "right": + return TextAlignment.RIGHT; + case "justify": + return TextAlignment.JUSTIFIED; + case "left": + default: + return TextAlignment.LEFT; + } + } + + #endregion + } +} diff --git a/XP.ReportEngine/Services/JsonTemplateEngine.cs b/XP.ReportEngine/Services/JsonTemplateEngine.cs new file mode 100644 index 0000000..d7f9036 --- /dev/null +++ b/XP.ReportEngine/Services/JsonTemplateEngine.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Services +{ + /// + /// JSON 模板引擎实现 | JSON template engine implementation + /// 负责加载、反序列化和验证 JSON 格式的报告模板 + /// Responsible for loading, deserializing and validating JSON report templates + /// + public class JsonTemplateEngine : ITemplateEngine + { + private readonly ILoggerService _logger; + + /// + /// 默认样式定义(当模板引用未定义的样式名称时使用) + /// Default style definition (used when template references undefined style name) + /// + public static readonly StyleDefinition DefaultStyle = new() + { + Font = null, + Size = 12f, + Bold = false, + Italic = false, + Color = "#000000", + Align = "left", + BackgroundColor = null + }; + + /// + /// 构造函数 | Constructor + /// + /// 日志服务 | Logger service + public JsonTemplateEngine(ILoggerService logger) + { + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + /// 加载并反序列化 JSON 模板文件 | Load and deserialize JSON template file + /// + /// 模板文件路径 | Template file path + /// 解析后的模板对象,文件不存在时返回 null | Parsed template object, null if file not found + public ReportTemplate LoadTemplate(string templatePath) + { + if (string.IsNullOrWhiteSpace(templatePath)) + { + _logger.Warn("模板文件路径为空 | Template file path is null or empty"); + return null; + } + + if (!File.Exists(templatePath)) + { + _logger.Warn("模板文件未找到: {Path} | Template file not found: {Path}", templatePath); + return null; + } + + _logger.Info("开始加载模板文件: {Path} | Loading template file: {Path}", templatePath); + + try + { + var json = File.ReadAllText(templatePath); + var template = JsonConvert.DeserializeObject(json); + + _logger.Info("模板文件加载成功 | Template file loaded successfully"); + return template; + } + catch (JsonReaderException ex) + { + // JSON 语法错误,包含错误位置信息 | JSON syntax error with position info + var message = $"模板 JSON 语法错误,行 {ex.LineNumber},位置 {ex.LinePosition}: {ex.Message} | " + + $"Template JSON syntax error at line {ex.LineNumber}, position {ex.LinePosition}: {ex.Message}"; + _logger.Error(ex, message); + throw new InvalidOperationException(message, ex); + } + catch (JsonSerializationException ex) + { + // JSON 反序列化错误 | JSON deserialization error + var message = $"模板 JSON 反序列化失败: {ex.Message} | Template JSON deserialization failed: {ex.Message}"; + _logger.Error(ex, message); + throw new InvalidOperationException(message, ex); + } + } + + /// + /// 验证模板结构完整性 | Validate template structure integrity + /// 检查 document、pages、styles 必需字段是否存在 + /// Checks if required fields (document, pages, styles) are present + /// + /// 待验证的模板 | Template to validate + /// 验证结果 | Validation result + public TemplateValidationResult Validate(ReportTemplate template) + { + if (template == null) + { + return TemplateValidationResult.Invalid("模板对象为 null | Template object is null"); + } + + var missingFields = new List(); + + if (template.Document == null) + { + missingFields.Add("document"); + } + + if (template.Pages == null || template.Pages.Count == 0) + { + missingFields.Add("pages"); + } + + if (template.Styles == null) + { + missingFields.Add("styles"); + } + + if (missingFields.Count > 0) + { + var fieldList = string.Join(", ", missingFields); + var message = $"模板缺少必需字段: {fieldList} | Template missing required fields: {fieldList}"; + _logger.Warn(message); + return TemplateValidationResult.Invalid(message); + } + + _logger.Info("模板验证通过 | Template validation passed"); + return TemplateValidationResult.Valid(); + } + + /// + /// 解析样式名称,未定义时回退为默认样式 | Resolve style name, fallback to default if undefined + /// + /// 报告模板 | Report template + /// 样式名称 | Style name + /// 解析后的样式定义 | Resolved style definition + public StyleDefinition ResolveStyle(ReportTemplate template, string styleName) + { + // 样式名称为空时直接返回默认样式 | Return default style if style name is empty + if (string.IsNullOrWhiteSpace(styleName)) + { + return DefaultStyle; + } + + // 模板或样式字典为空时返回默认样式 | Return default style if template or styles dictionary is null + if (template?.Styles == null) + { + _logger.Warn("模板样式字典为空,使用默认样式: {StyleName} | Template styles dictionary is null, using default style: {StyleName}", styleName); + return DefaultStyle; + } + + // 查找样式,找到则返回,否则回退为默认样式并记录警告 + // Look up style, return if found, otherwise fallback to default and log warning + if (template.Styles.TryGetValue(styleName, out var style)) + { + return style; + } + + _logger.Warn("未定义的样式名称 '{StyleName}',使用默认样式 | Undefined style name '{StyleName}', using default style", styleName); + return DefaultStyle; + } + } +} diff --git a/XP.ReportEngine/Services/PageLayoutEngine.cs b/XP.ReportEngine/Services/PageLayoutEngine.cs new file mode 100644 index 0000000..5bf2d19 --- /dev/null +++ b/XP.ReportEngine/Services/PageLayoutEngine.cs @@ -0,0 +1,522 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Services +{ + /// + /// 页面排版引擎实现 | Page layout engine implementation + /// 负责计算页面元素位置、处理分页和自适应布局 + /// Responsible for calculating element positions, handling pagination and adaptive layout + /// + public class PageLayoutEngine : ILayoutEngine + { + private readonly ILoggerService _logger; + private readonly JsonTemplateEngine _templateEngine; + + // A4 页面尺寸(mm)| A4 page dimensions (mm) + private const float A4Width = 210f; + private const float A4Height = 297f; + + // 默认行高估算(mm)| Default row height estimate (mm) + private const float DefaultRowHeight = 8f; + + // 默认文本元素高度(mm)| Default text element height (mm) + private const float DefaultTextHeight = 10f; + + // 默认分隔线高度(mm)| Default divider height (mm) + private const float DefaultDividerHeight = 2f; + + /// + /// 构造函数 | Constructor + /// + /// 日志服务 | Logger service + /// 模板引擎(用于样式解析)| Template engine (for style resolution) + public PageLayoutEngine(ILoggerService logger, JsonTemplateEngine templateEngine) + { + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + _templateEngine = templateEngine ?? throw new ArgumentNullException(nameof(templateEngine)); + } + + /// + /// 计算页面布局 | Calculate page layout + /// 遍历模板中所有页面和元素,根据定位方式计算最终坐标,处理分页和表格跨页 + /// Iterates through all pages and elements in template, calculates final coordinates based on positioning mode, + /// handles pagination and table page-splitting + /// + /// 绑定后的模板 | Bound template + /// 生成选项 | Generation options + /// 排版后的页面列表 | List of laid-out pages + public List CalculateLayout(ReportTemplate template, ReportGenerationOptions options) + { + if (template == null) throw new ArgumentNullException(nameof(template)); + + _logger.Info("开始排版计算 | Starting layout calculation"); + + var margins = template.Document?.Margins ?? new MarginSettings(); + var availableWidth = A4Width - margins.Left - margins.Right; + var availableHeight = A4Height - margins.Top - margins.Bottom; + + var pages = new List(); + var currentPageNumber = 1; + + if (template.Pages == null || template.Pages.Count == 0) + { + _logger.Warn("模板无页面定义 | Template has no page definitions"); + return pages; + } + + foreach (var templatePage in template.Pages) + { + if (templatePage.Elements == null || templatePage.Elements.Count == 0) + { + continue; + } + + // 分离绝对定位和流式定位元素 | Separate absolute and flow positioned elements + var absoluteElements = templatePage.Elements + .Where(e => string.Equals(e.Positioning, "absolute", StringComparison.OrdinalIgnoreCase)) + .ToList(); + var flowElements = templatePage.Elements + .Where(e => string.Equals(e.Positioning, "flow", StringComparison.OrdinalIgnoreCase)) + .ToList(); + + // 创建当前页面 | Create current page + var currentPage = new LayoutPage + { + PageNumber = currentPageNumber, + PageType = templatePage.Type, + Elements = new List() + }; + pages.Add(currentPage); + + // 处理绝对定位元素(不参与分页)| Process absolute positioned elements (no pagination) + foreach (var element in absoluteElements) + { + var layoutElement = ProcessAbsoluteElement(element, template, margins); + currentPage.Elements.Add(layoutElement); + } + + // 处理流式定位元素(参与分页)| Process flow positioned elements (with pagination) + var currentY = margins.Top; + + foreach (var element in flowElements) + { + var elementHeight = CalculateElementHeight(element); + var elementWidth = CalculateElementWidth(element, availableWidth); + + // 强制分页元素 | Forced page break element + if (string.Equals(element.Type, "pagebreak", StringComparison.OrdinalIgnoreCase)) + { + currentPageNumber++; + currentPage = new LayoutPage + { + PageNumber = currentPageNumber, + PageType = templatePage.Type, + Elements = new List() + }; + pages.Add(currentPage); + currentY = margins.Top; + continue; + } + + // 检查是否需要分页 | Check if pagination is needed + if (element.Type == "table" && element.Columns != null) + { + // 表格跨页拆分逻辑 | Table page-split logic + currentY = ProcessTableWithPageSplit( + element, template, margins, availableHeight, availableWidth, + currentY, pages, ref currentPage, ref currentPageNumber, templatePage.Type); + } + else + { + // 普通元素分页检查 | Normal element pagination check + if (currentY + elementHeight > margins.Top + availableHeight) + { + // 创建新页面 | Create new page + currentPageNumber++; + currentPage = new LayoutPage + { + PageNumber = currentPageNumber, + PageType = templatePage.Type, + Elements = new List() + }; + pages.Add(currentPage); + currentY = margins.Top; + } + + var layoutElement = CreateFlowLayoutElement( + element, template, margins, currentY, elementWidth, elementHeight); + currentPage.Elements.Add(layoutElement); + + // 累计 Y 坐标 | Accumulate Y coordinate + currentY += elementHeight; + } + } + + currentPageNumber++; + } + + _logger.Info("排版计算完成,共 {PageCount} 页 | Layout calculation completed, {PageCount} pages total", pages.Count); + return pages; + } + + /// + /// 处理绝对定位元素 | Process absolute positioned element + /// 元素坐标 = Position + Margins 偏移 + /// Element coordinates = Position + Margins offset + /// + private LayoutElement ProcessAbsoluteElement(TemplateElement element, ReportTemplate template, MarginSettings margins) + { + var x = margins.Left + (element.Position != null && element.Position.Length > 0 ? element.Position[0] : 0f); + var y = margins.Top + (element.Position != null && element.Position.Length > 1 ? element.Position[1] : 0f); + var width = element.Size != null && element.Size.Length > 0 ? element.Size[0] : 0f; + var height = element.Size != null && element.Size.Length > 1 ? element.Size[1] : 0f; + + // 图像等比缩放 | Image proportional scaling + if (element.Type == "image" && width > 0 && height > 0) + { + var scaled = CalculateScaledImageDimensions(width, height, width, height); + width = scaled.Width; + height = scaled.Height; + } + + var resolvedStyle = _templateEngine.ResolveStyle(template, element.Style); + + return new LayoutElement + { + Source = element, + X = x, + Y = y, + Width = width, + Height = height, + ResolvedStyle = resolvedStyle, + ResolvedContent = element.Content, + ResolvedTableData = element.TableData, + ResolvedImage = element.ImageData + }; + } + + /// + /// 创建流式定位的布局元素 | Create flow positioned layout element + /// + private LayoutElement CreateFlowLayoutElement( + TemplateElement element, ReportTemplate template, MarginSettings margins, + float currentY, float width, float height) + { + var x = margins.Left; + + // 如果元素有 Position 定义,使用 X 偏移 | If element has Position defined, use X offset + if (element.Position != null && element.Position.Length > 0) + { + x = margins.Left + element.Position[0]; + } + + // 图像等比缩放 | Image proportional scaling + if (element.Type == "image") + { + var targetWidth = width; + var targetHeight = height; + var imageWidth = element.Size != null && element.Size.Length > 0 ? element.Size[0] : width; + var imageHeight = element.Size != null && element.Size.Length > 1 ? element.Size[1] : height; + + if (imageWidth > 0 && imageHeight > 0 && targetWidth > 0 && targetHeight > 0) + { + var scaled = CalculateScaledImageDimensions(imageWidth, imageHeight, targetWidth, targetHeight); + width = scaled.Width; + height = scaled.Height; + } + } + + var resolvedStyle = _templateEngine.ResolveStyle(template, element.Style); + + return new LayoutElement + { + Source = element, + X = x, + Y = currentY, + Width = width, + Height = height, + ResolvedStyle = resolvedStyle, + ResolvedContent = element.Content, + ResolvedTableData = element.TableData, + ResolvedImage = element.ImageData + }; + } + + /// + /// 处理表格跨页拆分 | Process table with page-split + /// 按行高计算剩余空间,超出时拆分到新页面,续页重复表头行 + /// Calculate remaining space by row height, split to new page when exceeded, repeat header on continuation pages + /// + /// 处理后的当前 Y 坐标 | Current Y coordinate after processing + private float ProcessTableWithPageSplit( + TemplateElement element, ReportTemplate template, MarginSettings margins, + float availableHeight, float availableWidth, + float currentY, List pages, + ref LayoutPage currentPage, ref int currentPageNumber, string pageType) + { + var resolvedStyle = _templateEngine.ResolveStyle(template, element.Style); + var tableWidth = element.Size != null && element.Size.Length > 0 ? element.Size[0] : availableWidth; + + // 计算表头高度(1 行)| Calculate header height (1 row) + var headerHeight = DefaultRowHeight; + + // 获取表格数据行数 | Get table data row count + var tableData = GetTableDataFromElement(element); + var totalDataRows = tableData?.Count ?? 0; + + if (totalDataRows == 0) + { + // 空表格,仅渲染表头 | Empty table, render header only + var emptyTableHeight = headerHeight; + if (currentY + emptyTableHeight > margins.Top + availableHeight) + { + currentPageNumber++; + currentPage = new LayoutPage + { + PageNumber = currentPageNumber, + PageType = pageType, + Elements = new List() + }; + pages.Add(currentPage); + currentY = margins.Top; + } + + var emptyTableElement = new LayoutElement + { + Source = element, + X = margins.Left, + Y = currentY, + Width = tableWidth, + Height = emptyTableHeight, + ResolvedStyle = resolvedStyle, + ResolvedContent = element.Content, + ResolvedTableData = tableData + }; + currentPage.Elements.Add(emptyTableElement); + currentY += emptyTableHeight; + return currentY; + } + + // 计算当前页面剩余空间 | Calculate remaining space on current page + var remainingHeight = (margins.Top + availableHeight) - currentY; + var totalTableHeight = headerHeight + (totalDataRows * DefaultRowHeight); + + // 如果整个表格能放下,直接放置 | If entire table fits, place directly + if (totalTableHeight <= remainingHeight) + { + var tableElement = new LayoutElement + { + Source = element, + X = margins.Left, + Y = currentY, + Width = tableWidth, + Height = totalTableHeight, + ResolvedStyle = resolvedStyle, + ResolvedContent = element.Content, + ResolvedTableData = tableData + }; + currentPage.Elements.Add(tableElement); + currentY += totalTableHeight; + return currentY; + } + + // 需要跨页拆分 | Need to split across pages + var currentRowIndex = 0; + + while (currentRowIndex < totalDataRows) + { + // 计算当前页面可容纳的数据行数(需预留表头空间)| Calculate rows that fit on current page (reserve header space) + var currentRemainingHeight = (margins.Top + availableHeight) - currentY; + var rowsOnCurrentPage = (int)Math.Floor((currentRemainingHeight - headerHeight) / DefaultRowHeight); + + if (rowsOnCurrentPage <= 0) + { + // 当前页面空间不足以放置表头+至少一行数据,创建新页面 + // Current page doesn't have space for header + at least one data row, create new page + currentPageNumber++; + currentPage = new LayoutPage + { + PageNumber = currentPageNumber, + PageType = pageType, + Elements = new List() + }; + pages.Add(currentPage); + currentY = margins.Top; + currentRemainingHeight = availableHeight; + rowsOnCurrentPage = (int)Math.Floor((currentRemainingHeight - headerHeight) / DefaultRowHeight); + } + + // 确定本页实际放置的行数 | Determine actual rows to place on this page + var rowsToPlace = Math.Min(rowsOnCurrentPage, totalDataRows - currentRowIndex); + var splitData = tableData.Skip(currentRowIndex).Take(rowsToPlace).ToList(); + var splitHeight = headerHeight + (rowsToPlace * DefaultRowHeight); + + var splitElement = new LayoutElement + { + Source = element, + X = margins.Left, + Y = currentY, + Width = tableWidth, + Height = splitHeight, + ResolvedStyle = resolvedStyle, + ResolvedContent = element.Content, + ResolvedTableData = splitData + }; + currentPage.Elements.Add(splitElement); + currentY += splitHeight; + currentRowIndex += rowsToPlace; + + // 如果还有剩余行,创建新页面继续 | If there are remaining rows, create new page to continue + if (currentRowIndex < totalDataRows) + { + currentPageNumber++; + currentPage = new LayoutPage + { + PageNumber = currentPageNumber, + PageType = pageType, + Elements = new List() + }; + pages.Add(currentPage); + currentY = margins.Top; + } + } + + return currentY; + } + + /// + /// 计算图像等比缩放尺寸 | Calculate proportionally scaled image dimensions + /// 保持宽高比,确保缩放后的宽度和高度均不超过目标区域 + /// Maintain aspect ratio, ensure scaled width and height don't exceed target area + /// + /// 原始图像宽度 | Original image width + /// 原始图像高度 | Original image height + /// 目标区域宽度 | Target area width + /// 目标区域高度 | Target area height + /// 缩放后的尺寸 | Scaled dimensions + public (float Width, float Height) CalculateScaledImageDimensions( + float imageWidth, float imageHeight, float targetWidth, float targetHeight) + { + if (imageWidth <= 0 || imageHeight <= 0 || targetWidth <= 0 || targetHeight <= 0) + { + return (0f, 0f); + } + + // 如果图像已经在目标区域内,无需缩放 | If image already fits, no scaling needed + if (imageWidth <= targetWidth && imageHeight <= targetHeight) + { + return (imageWidth, imageHeight); + } + + // 计算宽度和高度的缩放比例,取较小值以确保两个维度都不超出 + // Calculate scale ratios for width and height, use the smaller one to ensure both dimensions fit + var widthRatio = targetWidth / imageWidth; + var heightRatio = targetHeight / imageHeight; + var scale = Math.Min(widthRatio, heightRatio); + + var scaledWidth = imageWidth * scale; + var scaledHeight = imageHeight * scale; + + return (scaledWidth, scaledHeight); + } + + /// + /// 计算元素高度 | Calculate element height + /// 根据元素类型和 Size 定义确定高度 + /// Determine height based on element type and Size definition + /// + private float CalculateElementHeight(TemplateElement element) + { + // 如果有明确的 Size 定义,使用 Size[1] 作为高度 | If Size is defined, use Size[1] as height + if (element.Size != null && element.Size.Length > 1 && element.Size[1] > 0) + { + return element.Size[1]; + } + + // 根据元素类型使用默认高度 | Use default height based on element type + return element.Type?.ToLowerInvariant() switch + { + "text" => DefaultTextHeight, + "divider" => DefaultDividerHeight, + "spacer" => element.Size is { Length: >= 2 } ? element.Size[1] : DefaultTextHeight, + "row" => CalculateRowHeight(element), + "pagebreak" => 0f, + "image" => DefaultTextHeight, + "table" => CalculateTableHeight(element), + _ => DefaultTextHeight + }; + } + + /// + /// 计算表格高度 | Calculate table height + /// 表头行 + 数据行数 × 默认行高 + /// Header row + data row count × default row height + /// + private float CalculateTableHeight(TemplateElement element) + { + var tableData = GetTableDataFromElement(element); + var dataRowCount = tableData?.Count ?? 0; + // 表头 1 行 + 数据行 | 1 header row + data rows + return DefaultRowHeight + (dataRowCount * DefaultRowHeight); + } + + /// + /// 计算 Row 容器高度 | Calculate row container height + /// 取子元素中最大高度,如果有 Size 定义则优先使用 + /// Uses max child height, or Size definition if available + /// + private float CalculateRowHeight(TemplateElement element) + { + // 如果 row 本身有 Size[1] 定义,直接使用 | If row has Size[1], use it directly + if (element.Size != null && element.Size.Length > 1 && element.Size[1] > 0) + { + return element.Size[1]; + } + + // 否则取子元素中最大高度 | Otherwise use max child height + if (element.Children == null || element.Children.Count == 0) + return DefaultTextHeight; + + float maxHeight = 0; + foreach (var child in element.Children) + { + float childHeight = DefaultTextHeight; + if (child.Size != null && child.Size.Length > 1 && child.Size[1] > 0) + { + childHeight = child.Size[1]; + } + if (childHeight > maxHeight) maxHeight = childHeight; + } + return maxHeight > 0 ? maxHeight : DefaultTextHeight; + } + + /// + /// 计算元素宽度 | Calculate element width + /// + private float CalculateElementWidth(TemplateElement element, float availableWidth) + { + if (element.Size != null && element.Size.Length > 0 && element.Size[0] > 0) + { + return element.Size[0]; + } + return availableWidth; + } + + /// + /// 从元素获取表格数据 | Get table data from element + /// 表格数据在数据绑定阶段通过 TableData 属性填充 + /// Table data is populated during data binding phase via TableData property + /// + private List> GetTableDataFromElement(TemplateElement element) + { + // 表格数据在数据绑定阶段已填充到 TemplateElement.TableData + // Table data is populated during data binding phase into TemplateElement.TableData + return element.TableData; + } + } +} diff --git a/XP.ReportEngine/Services/PdfReportGenerator.cs b/XP.ReportEngine/Services/PdfReportGenerator.cs new file mode 100644 index 0000000..81c31ce --- /dev/null +++ b/XP.ReportEngine/Services/PdfReportGenerator.cs @@ -0,0 +1,134 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Services +{ + /// + /// PDF 报告生成器实现 | PDF report generator implementation + /// 协调管线各阶段:模板加载 → 数据绑定 → 排版 → 渲染 → 保存 + /// Orchestrates pipeline phases: template loading → data binding → layout → rendering → saving + /// + public class PdfReportGenerator : IReportGenerator + { + private readonly ILoggerService _logger; + private readonly ITemplateEngine _templateEngine; + private readonly IDataBinder _dataBinder; + private readonly ILayoutEngine _layoutEngine; + private readonly IPdfRenderer _pdfRenderer; + + /// + /// 构造函数 | Constructor + /// + /// 日志服务 | Logger service + /// 模板引擎 | Template engine + /// 数据绑定器 | Data binder + /// 排版引擎 | Layout engine + /// PDF 渲染器 | PDF renderer + public PdfReportGenerator( + ILoggerService logger, + ITemplateEngine templateEngine, + IDataBinder dataBinder, + ILayoutEngine layoutEngine, + IPdfRenderer pdfRenderer) + { + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + _templateEngine = templateEngine ?? throw new ArgumentNullException(nameof(templateEngine)); + _dataBinder = dataBinder ?? throw new ArgumentNullException(nameof(dataBinder)); + _layoutEngine = layoutEngine ?? throw new ArgumentNullException(nameof(layoutEngine)); + _pdfRenderer = pdfRenderer ?? throw new ArgumentNullException(nameof(pdfRenderer)); + } + + /// + /// 异步生成 PDF 报告 | Generate PDF report asynchronously + /// 执行完整管线:模板加载 → 验证 → 数据绑定 → 排版计算 → PDF 渲染 → 文件保存(可选) + /// Executes full pipeline: template load → validate → data bind → layout → PDF render → save (optional) + /// + /// 报告上下文数据 | Report context data + /// 生成选项 | Generation options + /// 生成结果 | Generation result + public async Task GenerateAsync(ReportContext context, ReportGenerationOptions options) + { + try + { + _logger.Info("报告生成管线开始 | Report generation pipeline started"); + + // 阶段 1:加载模板 | Phase 1: Load template + _logger.Info("阶段 1:加载模板 | Phase 1: Loading template"); + var template = _templateEngine.LoadTemplate(options.TemplatePath); + if (template == null) + { + var errorMsg = $"模板文件未找到: {options.TemplatePath}"; + _logger.Error(null, "模板加载失败: {Path} | Template loading failed: {Path}", options.TemplatePath); + return ReportResult.Failure(errorMsg); + } + + var validation = _templateEngine.Validate(template); + if (!validation.IsValid) + { + var errorMsg = $"模板验证失败: {validation.ErrorMessage}"; + _logger.Error(null, "模板验证失败: {Message} | Template validation failed: {Message}", validation.ErrorMessage); + return ReportResult.Failure(errorMsg); + } + _logger.Info("阶段 1 完成:模板加载成功 | Phase 1 completed: Template loaded successfully"); + + // 阶段 2:数据绑定 | Phase 2: Data binding + _logger.Info("阶段 2:数据绑定 | Phase 2: Data binding"); + var boundTemplate = _dataBinder.Bind(template, context); + _logger.Info("阶段 2 完成:数据绑定成功 | Phase 2 completed: Data binding successful"); + + // 阶段 3:排版计算 | Phase 3: Layout calculation + _logger.Info("阶段 3:排版计算 | Phase 3: Layout calculation"); + var pages = _layoutEngine.CalculateLayout(boundTemplate, options); + _logger.Info("阶段 3 完成:排版计算成功,共 {PageCount} 页 | Phase 3 completed: Layout calculated, {PageCount} pages", pages.Count); + + // 阶段 4:PDF 渲染 | Phase 4: PDF rendering + _logger.Info("阶段 4:PDF 渲染 | Phase 4: PDF rendering"); + var stream = _pdfRenderer.Render(pages, options, boundTemplate); + _logger.Info("阶段 4 完成:PDF 渲染成功 | Phase 4 completed: PDF rendering successful"); + + // 阶段 5:保存文件(可选)| Phase 5: Save file (optional) + if (!string.IsNullOrEmpty(options.OutputFilePath)) + { + _logger.Info("阶段 5:保存文件 | Phase 5: Saving file"); + await SaveToFileAsync(stream, options.OutputFilePath); + _logger.Info("阶段 5 完成:文件保存成功 {Path} | Phase 5 completed: File saved successfully {Path}", options.OutputFilePath); + } + + _logger.Info("报告生成管线完成 | Report generation pipeline completed"); + return ReportResult.Success(stream); + } + catch (Exception ex) + { + _logger.Error(ex, "报告生成失败 | Report generation failed: {Message}", ex.Message); + return ReportResult.Failure($"报告生成过程中发生错误: {ex.Message}", ex); + } + } + + /// + /// 将 MemoryStream 保存到文件 | Save MemoryStream to file + /// + /// PDF 内存流 | PDF memory stream + /// 输出文件路径 | Output file path + private async Task SaveToFileAsync(MemoryStream stream, string filePath) + { + // 确保输出目录存在 | Ensure output directory exists + var directory = Path.GetDirectoryName(filePath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + // 重置流位置后写入文件 | Reset stream position before writing to file + stream.Position = 0; + using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None); + await stream.CopyToAsync(fileStream); + + // 重置流位置以便后续使用 | Reset stream position for subsequent use + stream.Position = 0; + } + } +} diff --git a/XP.ReportEngine/Services/ProcessorDataAdapter.cs b/XP.ReportEngine/Services/ProcessorDataAdapter.cs new file mode 100644 index 0000000..5e794e5 --- /dev/null +++ b/XP.ReportEngine/Services/ProcessorDataAdapter.cs @@ -0,0 +1,533 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Services +{ + /// + /// 处理器数据适配器实现 | Processor data adapter implementation + /// 将 XP.ImageProcessing 的 ProcessorOutput 转换为 ReportContext + /// Converts XP.ImageProcessing ProcessorOutput to ReportContext + /// + public class ProcessorDataAdapter : IReportDataAdapter + { + private readonly ILoggerService _logger; + + // 处理器类型常量 | Processor type constants + private const string LineMeasurementProcessor = "LineMeasurementProcessor"; + private const string BgaVoidRateProcessor = "BgaVoidRateProcessor"; + private const string VoidMeasurementProcessor = "VoidMeasurementProcessor"; + private const string FillRateProcessor = "FillRateProcessor"; + + public ProcessorDataAdapter(ILoggerService logger) + { + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + /// 将处理器输出数据适配为报告上下文 | Adapt processor output data to report context + /// + public ReportContext Adapt(List processorOutputs, ReportMetadata metadata) + { + if (processorOutputs == null) throw new ArgumentNullException(nameof(processorOutputs)); + if (metadata == null) throw new ArgumentNullException(nameof(metadata)); + + _logger.Info("开始数据适配,处理器数量: {Count} | Starting data adaptation, processor count: {Count}", processorOutputs.Count); + + var context = new ReportContext + { + Metadata = metadata, + ResultGroups = new List(), + Images = new Dictionary(), + Properties = new Dictionary() + }; + + // 多处理器输出聚合逻辑:每个 ProcessorOutput 生成一个 InspectionResultGroup | Aggregation: each ProcessorOutput becomes one InspectionResultGroup + for (var i = 0; i < processorOutputs.Count; i++) + { + var output = processorOutputs[i]; + if (output == null) + { + _logger.Warn("处理器输出为 null,索引: {Index},已跳过 | Processor output is null at index: {Index}, skipped", i); + continue; + } + + var group = AdaptProcessorOutput(output, i); + context.ResultGroups.Add(group); + + // 将结果数据扁平化到 Properties(供模板 ${key} 表达式绑定) + // Flatten result data to Properties (for template ${key} expression binding) + if (group.Data != null) + { + foreach (var kvp in group.Data) + { + context.Properties[kvp.Key] = kvp.Value; + } + } + + // 将 Classification 也放入 Properties | Also put Classification into Properties + if (!string.IsNullOrEmpty(group.Classification)) + { + context.Properties["classification"] = group.Classification; + } + + // 将表格数据以模板期望的 dataKey 存入 Properties + // Store table data with template-expected dataKey into Properties + if (group.TableRows != null && group.TableRows.Count > 0) + { + var tableKey = GetTableDataKey(output.ProcessorType); + if (!string.IsNullOrEmpty(tableKey)) + { + context.Properties[tableKey] = group.TableRows; + } + } + + // 关联标注图像(使用模板期望的 dataKey) + // Associate annotated image (using template-expected dataKey) + if (output.AnnotatedImage != null) + { + var imageKey = GetImageDataKey(output.ProcessorType); + context.Images[imageKey] = output.AnnotatedImage; + + // 同时保留原始键名以兼容其他调用方 | Also keep original key for other callers + var originalKey = $"{output.ProcessorType}_{i}_annotated"; + context.Images[originalKey] = output.AnnotatedImage; + } + } + + _logger.Info("数据适配完成,生成 {Count} 个结果分组 | Data adaptation completed, generated {Count} result groups", context.ResultGroups.Count); + return context; + } + + /// + /// 根据处理器类型分发适配逻辑 | Dispatch adaptation logic by processor type + /// + private InspectionResultGroup AdaptProcessorOutput(ProcessorOutput output, int index) + { + var sourceId = $"{output.ProcessorType}_{index}"; + + return output.ProcessorType switch + { + LineMeasurementProcessor => AdaptLineMeasurement(output, sourceId), + BgaVoidRateProcessor => AdaptBgaVoidRate(output, sourceId), + VoidMeasurementProcessor => AdaptVoidMeasurement(output, sourceId), + FillRateProcessor => AdaptFillRate(output, sourceId), + _ => AdaptGeneric(output, sourceId) + }; + } + + #region LineMeasurementProcessor 适配 | LineMeasurementProcessor Adaptation + + /// + /// 适配线测量处理器输出 | Adapt line measurement processor output + /// 提取 MeasurementType、Point1、Point2、PixelDistance、ActualDistance、Unit、Angle + /// + private InspectionResultGroup AdaptLineMeasurement(ProcessorOutput output, string sourceId) + { + _logger.Debug("适配 LineMeasurementProcessor 输出,SourceId: {SourceId} | Adapting LineMeasurementProcessor output, SourceId: {SourceId}", sourceId); + + var data = output.OutputData ?? new Dictionary(); + var group = new InspectionResultGroup + { + ProcessorType = LineMeasurementProcessor, + SourceId = sourceId, + Classification = string.Empty, + Data = new Dictionary + { + ["measurementType"] = GetValueOrDefault(data, "MeasurementType", string.Empty), + ["point1"] = GetValueOrDefault(data, "Point1", null), + ["point2"] = GetValueOrDefault(data, "Point2", null), + ["pixelDistance"] = GetValueOrDefault(data, "PixelDistance", 0.0), + ["actualDistance"] = GetValueOrDefault(data, "ActualDistance", 0.0), + ["unit"] = GetValueOrDefault(data, "Unit", string.Empty), + ["angle"] = GetValueOrDefault(data, "Angle", 0.0) + }, + TableRows = new List>() + }; + + return group; + } + + #endregion + + #region BgaVoidRateProcessor 适配 | BgaVoidRateProcessor Adaptation + + /// + /// 适配 BGA 气泡率处理器输出 | Adapt BGA void rate processor output + /// 提取 BgaCount、BgaBalls 列表转 TableRows、VoidRate、FillRate、TotalBgaArea、TotalVoidArea、Classification、VoidLimit + /// + private InspectionResultGroup AdaptBgaVoidRate(ProcessorOutput output, string sourceId) + { + _logger.Debug("适配 BgaVoidRateProcessor 输出,SourceId: {SourceId} | Adapting BgaVoidRateProcessor output, SourceId: {SourceId}", sourceId); + + var data = output.OutputData ?? new Dictionary(); + var group = new InspectionResultGroup + { + ProcessorType = BgaVoidRateProcessor, + SourceId = sourceId, + Classification = GetValueOrDefault(data, "Classification", string.Empty), + Data = new Dictionary + { + ["bgaCount"] = GetValueOrDefault(data, "BgaCount", 0), + ["voidRate"] = GetValueOrDefault(data, "VoidRate", 0.0), + ["fillRate"] = GetValueOrDefault(data, "FillRate", 0.0), + ["totalBgaArea"] = GetValueOrDefault(data, "TotalBgaArea", 0.0), + ["totalVoidArea"] = GetValueOrDefault(data, "TotalVoidArea", 0.0), + ["voidLimit"] = GetValueOrDefault(data, "VoidLimit", 0.0) + }, + TableRows = ConvertBgaBallsToTableRows(data) + }; + + return group; + } + + /// + /// 将 BgaBalls 列表转换为表格行 | Convert BgaBalls list to table rows + /// 每个焊球一行,包含 index、voidRate、area、classification + /// + private List> ConvertBgaBallsToTableRows(Dictionary data) + { + var tableRows = new List>(); + var bgaBalls = GetListValue(data, "BgaBalls"); + + if (bgaBalls == null || bgaBalls.Count == 0) + { + return tableRows; + } + + for (var i = 0; i < bgaBalls.Count; i++) + { + var ball = bgaBalls[i]; + var row = new Dictionary + { + ["index"] = i + 1, + ["voidRate"] = GetNestedValue(ball, "VoidRate", 0.0), + ["area"] = GetNestedValue(ball, "Area", 0.0), + ["classification"] = GetNestedValue(ball, "Classification", string.Empty) + }; + tableRows.Add(row); + } + + return tableRows; + } + + #endregion + + #region VoidMeasurementProcessor 适配 | VoidMeasurementProcessor Adaptation + + /// + /// 适配空隙测量处理器输出 | Adapt void measurement processor output + /// 提取 RoiArea、TotalVoidArea、VoidRate、VoidLimit、VoidCount、MaxVoidArea、Classification、Voids 列表转 TableRows + /// + private InspectionResultGroup AdaptVoidMeasurement(ProcessorOutput output, string sourceId) + { + _logger.Debug("适配 VoidMeasurementProcessor 输出,SourceId: {SourceId} | Adapting VoidMeasurementProcessor output, SourceId: {SourceId}", sourceId); + + var data = output.OutputData ?? new Dictionary(); + var group = new InspectionResultGroup + { + ProcessorType = VoidMeasurementProcessor, + SourceId = sourceId, + Classification = GetValueOrDefault(data, "Classification", string.Empty), + Data = new Dictionary + { + ["roiArea"] = GetValueOrDefault(data, "RoiArea", 0.0), + ["totalVoidArea"] = GetValueOrDefault(data, "TotalVoidArea", 0.0), + ["voidRate"] = GetValueOrDefault(data, "VoidRate", 0.0), + ["voidLimit"] = GetValueOrDefault(data, "VoidLimit", 0.0), + ["voidCount"] = GetValueOrDefault(data, "VoidCount", 0), + ["maxVoidArea"] = GetValueOrDefault(data, "MaxVoidArea", 0.0) + }, + TableRows = ConvertVoidsToTableRows(data) + }; + + return group; + } + + /// + /// 将 Voids 列表转换为表格行 | Convert Voids list to table rows + /// 每个空隙一行,包含 index、area、areaPercent、centerX、centerY + /// + private List> ConvertVoidsToTableRows(Dictionary data) + { + var tableRows = new List>(); + var voids = GetListValue(data, "Voids"); + + if (voids == null || voids.Count == 0) + { + return tableRows; + } + + for (var i = 0; i < voids.Count; i++) + { + var voidItem = voids[i]; + var row = new Dictionary + { + ["index"] = i + 1, + ["area"] = GetNestedValue(voidItem, "Area", 0.0), + ["areaPercent"] = GetNestedValue(voidItem, "AreaPercent", 0.0), + ["centerX"] = GetNestedValue(voidItem, "CenterX", 0.0), + ["centerY"] = GetNestedValue(voidItem, "CenterY", 0.0) + }; + tableRows.Add(row); + } + + return tableRows; + } + + #endregion + + #region FillRateProcessor 适配 | FillRateProcessor Adaptation + + /// + /// 适配填锡率处理器输出 | Adapt fill rate processor output + /// 提取 FillRate、VoidRate、FullDistance、FillDistance、THTLimit、Classification、E1-E4 椭圆几何数据 + /// + private InspectionResultGroup AdaptFillRate(ProcessorOutput output, string sourceId) + { + _logger.Debug("适配 FillRateProcessor 输出,SourceId: {SourceId} | Adapting FillRateProcessor output, SourceId: {SourceId}", sourceId); + + var data = output.OutputData ?? new Dictionary(); + var group = new InspectionResultGroup + { + ProcessorType = FillRateProcessor, + SourceId = sourceId, + Classification = GetValueOrDefault(data, "Classification", string.Empty), + Data = new Dictionary + { + ["fillRate"] = GetValueOrDefault(data, "FillRate", 0.0), + ["voidRate"] = GetValueOrDefault(data, "VoidRate", 0.0), + ["fullDistance"] = GetValueOrDefault(data, "FullDistance", 0.0), + ["fillDistance"] = GetValueOrDefault(data, "FillDistance", 0.0), + ["thtLimit"] = GetValueOrDefault(data, "THTLimit", 0.0), + ["e1"] = GetValueOrDefault(data, "E1", null), + ["e2"] = GetValueOrDefault(data, "E2", null), + ["e3"] = GetValueOrDefault(data, "E3", null), + ["e4"] = GetValueOrDefault(data, "E4", null) + }, + TableRows = new List>() + }; + + return group; + } + + #endregion + + #region 通用适配 | Generic Adaptation + + /// + /// 通用处理器适配(未知类型)| Generic processor adaptation (unknown type) + /// 将所有 OutputData 键值对直接映射到 Data 字典 + /// + private InspectionResultGroup AdaptGeneric(ProcessorOutput output, string sourceId) + { + _logger.Warn("未知处理器类型: {ProcessorType},使用通用适配 | Unknown processor type: {ProcessorType}, using generic adaptation", output.ProcessorType); + + var data = output.OutputData ?? new Dictionary(); + var group = new InspectionResultGroup + { + ProcessorType = output.ProcessorType ?? "Unknown", + SourceId = sourceId, + Classification = GetValueOrDefault(data, "Classification", string.Empty), + Data = new Dictionary(), + TableRows = new List>() + }; + + // 将所有键值对转为小驼峰命名映射 | Map all key-value pairs with camelCase naming + foreach (var kvp in data) + { + var camelKey = ToCamelCase(kvp.Key); + group.Data[camelKey] = kvp.Value; + } + + return group; + } + + #endregion + + #region 辅助方法 | Helper Methods + + /// + /// 从字典中获取值,缺失时使用默认值并记录警告 | Get value from dictionary, use default and log warning if missing + /// + private T GetValueOrDefault(Dictionary data, string key, T defaultValue) + { + if (data == null || !data.TryGetValue(key, out var value) || value == null) + { + _logger.Warn("处理器输出缺少键: {Key},使用默认值: {Default} | Processor output missing key: {Key}, using default: {Default}", key, defaultValue); + return defaultValue; + } + + try + { + return ConvertValue(value); + } + catch (Exception ex) + { + _logger.Warn("键 {Key} 的值类型转换失败: {Message},使用默认值 | Value type conversion failed for key {Key}: {Message}, using default", key, ex.Message); + return defaultValue; + } + } + + /// + /// 从字典中获取列表值 | Get list value from dictionary + /// + private IList GetListValue(Dictionary data, string key) + { + if (data == null || !data.TryGetValue(key, out var value) || value == null) + { + _logger.Warn("处理器输出缺少列表键: {Key},返回空列表 | Processor output missing list key: {Key}, returning empty list", key); + return null; + } + + if (value is IList list) + { + return list; + } + + _logger.Warn("键 {Key} 的值不是列表类型 | Value for key {Key} is not a list type", key); + return null; + } + + /// + /// 从嵌套对象中获取属性值 | Get property value from nested object + /// + private T GetNestedValue(object obj, string propertyName, T defaultValue) + { + if (obj == null) return defaultValue; + + // 字典访问 | Dictionary access + if (obj is IDictionary dict) + { + if (dict.TryGetValue(propertyName, out var dictValue) && dictValue != null) + { + try + { + return ConvertValue(dictValue); + } + catch + { + return defaultValue; + } + } + return defaultValue; + } + + // 反射访问 | Reflection access + var type = obj.GetType(); + var propInfo = type.GetProperty(propertyName, + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase); + if (propInfo != null) + { + try + { + var value = propInfo.GetValue(obj); + if (value == null) return defaultValue; + return ConvertValue(value); + } + catch + { + return defaultValue; + } + } + + return defaultValue; + } + + /// + /// 类型转换辅助方法 | Type conversion helper + /// + private T ConvertValue(object value) + { + if (value == null) return default; + + var targetType = typeof(T); + + // 直接类型匹配 | Direct type match + if (value is T typedValue) + { + return typedValue; + } + + // 处理 nullable 类型 | Handle nullable types + var underlyingType = Nullable.GetUnderlyingType(targetType) ?? targetType; + + // object 类型直接返回 | Return directly for object type + if (underlyingType == typeof(object)) + { + return (T)value; + } + + // 数值类型转换 | Numeric type conversion + if (underlyingType == typeof(double)) + { + return (T)(object)Convert.ToDouble(value); + } + if (underlyingType == typeof(int)) + { + return (T)(object)Convert.ToInt32(value); + } + if (underlyingType == typeof(float)) + { + return (T)(object)Convert.ToSingle(value); + } + if (underlyingType == typeof(long)) + { + return (T)(object)Convert.ToInt64(value); + } + + // 字符串转换 | String conversion + if (underlyingType == typeof(string)) + { + return (T)(object)value.ToString(); + } + + // 通用转换 | General conversion + return (T)Convert.ChangeType(value, underlyingType); + } + + /// + /// 将 PascalCase 转换为 camelCase | Convert PascalCase to camelCase + /// + private string ToCamelCase(string input) + { + if (string.IsNullOrEmpty(input)) return input; + if (input.Length == 1) return input.ToLowerInvariant(); + return char.ToLowerInvariant(input[0]) + input.Substring(1); + } + + /// + /// 根据处理器类型获取模板中对应的图像 dataKey | Get template image dataKey by processor type + /// + private static string GetImageDataKey(string processorType) + { + return processorType switch + { + LineMeasurementProcessor => "lineMeasurementImage", + BgaVoidRateProcessor => "bgaInspectionImage", + VoidMeasurementProcessor => "voidInspectionImage", + FillRateProcessor => "viaFillImage", + _ => $"{processorType}_image" + }; + } + + /// + /// 根据处理器类型获取模板中对应的表格 dataKey | Get template table dataKey by processor type + /// + private static string GetTableDataKey(string processorType) + { + return processorType switch + { + BgaVoidRateProcessor => "bgaBallsTable", + VoidMeasurementProcessor => "voidsTable", + _ => null + }; + } + + #endregion + } +} diff --git a/XP.ReportEngine/Services/ReportGeneratorFactory.cs b/XP.ReportEngine/Services/ReportGeneratorFactory.cs new file mode 100644 index 0000000..c27623f --- /dev/null +++ b/XP.ReportEngine/Services/ReportGeneratorFactory.cs @@ -0,0 +1,53 @@ +using System; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Services +{ + /// + /// 报告生成器工厂实现 | Report generator factory implementation + /// 根据输出格式创建对应的报告生成器实例 + /// Creates report generator instances based on output format + /// + public class ReportGeneratorFactory : IReportGeneratorFactory + { + private readonly ILoggerService _logger; + private readonly IReportGenerator _pdfReportGenerator; + + /// + /// 构造函数 | Constructor + /// + /// 日志服务 | Logger service + /// PDF 报告生成器 | PDF report generator + public ReportGeneratorFactory(ILoggerService logger, IReportGenerator pdfReportGenerator) + { + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + _pdfReportGenerator = pdfReportGenerator ?? throw new ArgumentNullException(nameof(pdfReportGenerator)); + } + + /// + /// 根据输出格式创建生成器 | Create generator by output format + /// 当前仅支持 PDF 格式,未来可扩展 Excel/CSV + /// Currently only supports PDF format, extensible for Excel/CSV in the future + /// + /// 输出格式 | Output format + /// 对应格式的报告生成器 | Report generator for the specified format + /// 当请求不支持的格式时抛出 | Thrown when unsupported format is requested + public IReportGenerator Create(ReportOutputFormat format) + { + _logger.Info("创建报告生成器,格式: {Format} | Creating report generator, format: {Format}", format); + + switch (format) + { + case ReportOutputFormat.Pdf: + return _pdfReportGenerator; + + default: + var message = $"不支持的报告输出格式: {format} | Unsupported report output format: {format}"; + _logger.Error(null, message); + throw new NotSupportedException(message); + } + } + } +} diff --git a/XP.ReportEngine/Services/ReportIdGenerator.cs b/XP.ReportEngine/Services/ReportIdGenerator.cs new file mode 100644 index 0000000..4454246 --- /dev/null +++ b/XP.ReportEngine/Services/ReportIdGenerator.cs @@ -0,0 +1,80 @@ +using System; + +namespace XP.ReportEngine.Services +{ + /// + /// 报告编号生成器 | Report ID generator + /// 生成格式为 RPT-yyyyMMdd-NNN 的唯一报告编号 + /// Generates unique report IDs in format: RPT-yyyyMMdd-NNN + /// 线程安全,每日自动重置计数器 + /// Thread-safe with daily counter reset + /// + public class ReportIdGenerator + { + private readonly object _lock = new(); + private int _dailyCounter; + private string _currentDate; + + /// + /// 构造函数 | Constructor + /// + public ReportIdGenerator() + { + _currentDate = DateTime.Now.ToString("yyyyMMdd"); + _dailyCounter = 0; + } + + /// + /// 生成下一个唯一报告编号 | Generate next unique report ID + /// 格式:RPT-yyyyMMdd-NNN(如 RPT-20250101-001) + /// Format: RPT-yyyyMMdd-NNN (e.g., RPT-20250101-001) + /// + /// 唯一报告编号 | Unique report ID + public string GenerateNext() + { + lock (_lock) + { + var today = DateTime.Now.ToString("yyyyMMdd"); + + // 日期变更时重置计数器 | Reset counter when date changes + if (today != _currentDate) + { + _currentDate = today; + _dailyCounter = 0; + } + + _dailyCounter++; + return $"RPT-{_currentDate}-{_dailyCounter:D3}"; + } + } + + /// + /// 根据指定时间戳生成报告编号 | Generate report ID with specified timestamp + /// 用于需要指定日期的场景(如补录报告) + /// Used for scenarios requiring specific dates (e.g., backfilling reports) + /// + /// 指定的时间戳 | Specified timestamp + /// 唯一报告编号 | Unique report ID + public string GenerateForDate(DateTime timestamp) + { + lock (_lock) + { + var dateStr = timestamp.ToString("yyyyMMdd"); + + // 如果指定日期与当前日期相同,使用当前计数器 + // If specified date matches current date, use current counter + if (dateStr == _currentDate) + { + _dailyCounter++; + return $"RPT-{_currentDate}-{_dailyCounter:D3}"; + } + + // 如果指定日期与当前日期不同,更新日期并重置计数器 + // If specified date differs from current date, update date and reset counter + _currentDate = dateStr; + _dailyCounter = 1; + return $"RPT-{_currentDate}-{_dailyCounter:D3}"; + } + } + } +} diff --git a/XP.ReportEngine/Services/ReportService.cs b/XP.ReportEngine/Services/ReportService.cs new file mode 100644 index 0000000..20c68b5 --- /dev/null +++ b/XP.ReportEngine/Services/ReportService.cs @@ -0,0 +1,390 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using XP.Common.Logging.Interfaces; +using XP.ReportEngine.Configs; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; + +namespace XP.ReportEngine.Services +{ + /// + /// 报告服务实现(门面)| Report service implementation (Facade) + /// 协调报告生成的完整流程,将 UI 无关的业务逻辑封装为可复用服务 + /// Orchestrates the complete report generation workflow, encapsulating UI-independent business logic as a reusable service + /// + public class ReportService : IReportService + { + private readonly IReportGenerator _reportGenerator; + private readonly IReportDataAdapter _dataAdapter; + private readonly ILoggerService _logger; + private readonly ReportIdGenerator _reportIdGenerator; + private readonly ReportConfig _reportConfig; + + /// + /// 生成互斥锁,防止并发渲染导致 iText7 字体对象跨文档引用错误 + /// Generation mutex to prevent concurrent rendering causing iText7 cross-document font reference errors + /// + private readonly SemaphoreSlim _generateLock = new(1, 1); + + /// + /// 构造函数 | Constructor + /// + /// 报告生成器 | Report generator + /// 数据适配器 | Data adapter + /// 日志服务 | Logger service + /// 报告编号生成器 | Report ID generator + /// 报告配置 | Report config + public ReportService( + IReportGenerator reportGenerator, + IReportDataAdapter dataAdapter, + ILoggerService logger, + ReportIdGenerator reportIdGenerator, + ReportConfig reportConfig) + { + _reportGenerator = reportGenerator ?? throw new ArgumentNullException(nameof(reportGenerator)); + _dataAdapter = dataAdapter ?? throw new ArgumentNullException(nameof(dataAdapter)); + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + _reportIdGenerator = reportIdGenerator ?? throw new ArgumentNullException(nameof(reportIdGenerator)); + _reportConfig = reportConfig ?? throw new ArgumentNullException(nameof(reportConfig)); + } + + /// + /// 生成报告 | Generate report + /// + public async Task GenerateAsync(ReportRequest request) + { + if (request == null) + throw new ArgumentNullException(nameof(request)); + + // 获取互斥锁,防止并发渲染 | Acquire mutex to prevent concurrent rendering + await _generateLock.WaitAsync(); + try + { + _logger.Info("报告服务开始生成 | Report service starting generation"); + + // 步骤 1:生成报告编号 | Step 1: Generate report ID + var reportId = GenerateReportId(request); + _logger.Info("报告编号: {ReportId} | Report ID: {ReportId}", reportId); + + // 步骤 2:确定输出路径 | Step 2: Determine output path + var outputPath = ResolveOutputPath(request, reportId); + _logger.Info("输出路径: {Path} | Output path: {Path}", outputPath); + + // 步骤 3:数据适配 | Step 3: Data adaptation + var metadata = request.Metadata ?? new ReportMetadata(); + if (string.IsNullOrEmpty(metadata.ReportId)) + { + metadata.ReportId = reportId; + } + if (metadata.InspectionDate == default) + { + metadata.InspectionDate = DateTime.Now; + } + + var context = _dataAdapter.Adapt(request.ProcessorOutputs ?? new List(), metadata); + _logger.Info("数据适配完成 | Data adaptation completed"); + + // 步骤 4:注入额外图像 | Step 4: Inject additional images + InjectAdditionalImages(context, request); + + // 步骤 5:注入配置中的 Logo 和公司信息 | Step 5: Inject logo and company info from config + InjectConfigData(context); + + // 步骤 6:注入自定义属性 | Step 6: Inject custom properties + InjectCustomProperties(context, request); + + // 步骤 7:生成首页汇总表 | Step 7: Generate homepage summary table + context.Properties["summaryTable"] = CreateSummaryTableData(context); + + // 步骤 8:调用管线生成 PDF | Step 8: Call pipeline to generate PDF + var templatePath = _reportConfig.GetResolvedTemplatePath(); + var options = new ReportGenerationOptions + { + TemplatePath = templatePath, + OutputFilePath = outputPath, + Format = ReportOutputFormat.Pdf + }; + + var genResult = await _reportGenerator.GenerateAsync(context, options); + + // 步骤 9:处理结果 | Step 9: Handle result + if (genResult.IsSuccess) + { + _logger.Info("报告生成成功: {Path} | Report generated successfully: {Path}", outputPath); + return ReportServiceResult.Success(outputPath, reportId); + } + else + { + _logger.Error(null, "报告生成失败: {Message} | Report generation failed: {Message}", genResult.ErrorMessage); + return ReportServiceResult.Failure(genResult.ErrorMessage, genResult.Exception); + } + } + catch (Exception ex) + { + _logger.Error(ex, "报告服务异常: {Message} | Report service exception: {Message}", ex.Message); + return ReportServiceResult.Failure($"报告生成过程中发生异常: {ex.Message}", ex); + } + finally + { + _generateLock.Release(); + } + } + + /// + /// 预热报告引擎 | Warm up report engine + /// 通过生成一个最小化的空白 PDF 来触发所有一次性初始化: + /// iText7 程序集加载、BouncyCastle 注册、字体子系统初始化、JIT 编译 + /// + public async Task WarmUpAsync() + { + // 获取互斥锁,确保预热与正式生成不并发 | Acquire mutex to ensure warm-up doesn't overlap with generation + await _generateLock.WaitAsync(); + try + { + _logger.Info("报告引擎预热开始 | Report engine warm-up started"); + + await Task.Run(() => + { + // 加载模板(触发 JSON 反序列化 JIT)| Load template (triggers JSON deserialization JIT) + var templatePath = _reportConfig.GetResolvedTemplatePath(); + if (!File.Exists(templatePath)) + { + _logger.Warn("预热跳过:模板文件不存在 {Path} | Warm-up skipped: template not found {Path}", templatePath); + return; + } + + // 构建最小上下文 | Build minimal context + var context = new ReportContext + { + Metadata = new ReportMetadata + { + ReportId = "WARMUP", + InspectionDate = DateTime.Now, + SampleName = "WarmUp", + OperatorName = "System" + }, + ResultGroups = new List(), + Images = new Dictionary(), + Properties = new Dictionary + { + ["summaryTable"] = new List>() + } + }; + + var options = new ReportGenerationOptions + { + TemplatePath = templatePath, + OutputFilePath = null, // 不保存文件 | Don't save file + Format = ReportOutputFormat.Pdf + }; + + // 执行完整管线(触发 iText7 初始化 + 字体加载 + JIT) + // Execute full pipeline (triggers iText7 init + font loading + JIT) + var result = _reportGenerator.GenerateAsync(context, options).GetAwaiter().GetResult(); + + // 释放预热产生的流 | Dispose warm-up stream + result.PdfStream?.Dispose(); + }); + + _logger.Info("报告引擎预热完成 | Report engine warm-up completed"); + } + catch (Exception ex) + { + // 预热失败不影响正常功能 | Warm-up failure doesn't affect normal functionality + _logger.Warn("报告引擎预热失败(不影响正常使用)| Report engine warm-up failed (doesn't affect normal usage): {Message}", ex.Message); + } + finally + { + _generateLock.Release(); + } + } + + #region 私有方法 | Private Methods + + /// + /// 生成报告编号 | Generate report ID + /// 优先使用请求中已有的 ReportId,否则自动生成 + /// Prefer existing ReportId from request, otherwise auto-generate + /// + private string GenerateReportId(ReportRequest request) + { + // 如果 Metadata 中已有 ReportId,直接使用 | If Metadata already has ReportId, use it directly + if (request.Metadata != null && !string.IsNullOrEmpty(request.Metadata.ReportId)) + { + return request.Metadata.ReportId; + } + + // 如果 FileNameParameters 中已有 ReportId,直接使用 | If FileNameParameters already has ReportId, use it + if (request.FileNameParameters != null && + request.FileNameParameters.TryGetValue("ReportId", out var existingId) && + !string.IsNullOrEmpty(existingId)) + { + return existingId; + } + + // 自动生成 | Auto-generate + return _reportIdGenerator.GenerateNext(); + } + + /// + /// 解析输出文件路径 | Resolve output file path + /// + private string ResolveOutputPath(ReportRequest request, string reportId) + { + // 如果请求中指定了输出路径,直接使用 | If output path specified in request, use it directly + if (!string.IsNullOrEmpty(request.OutputFilePath)) + { + // 确保目录存在 | Ensure directory exists + var dir = Path.GetDirectoryName(request.OutputFilePath); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + return request.OutputFilePath; + } + + // 使用配置和参数自动生成路径 | Auto-generate path using config and parameters + var fileNameParams = request.FileNameParameters ?? new Dictionary(); + + // 确保 ReportId 在参数中 | Ensure ReportId is in parameters + if (!fileNameParams.ContainsKey("ReportId")) + { + fileNameParams["ReportId"] = reportId; + } + + return _reportConfig.ResolveOutputFilePath(fileNameParams); + } + + /// + /// 注入额外图像到上下文 | Inject additional images into context + /// + private void InjectAdditionalImages(ReportContext context, ReportRequest request) + { + if (request.AdditionalImages == null || request.AdditionalImages.Count == 0) + return; + + foreach (var kvp in request.AdditionalImages) + { + if (kvp.Value != null) + { + context.Images[kvp.Key] = kvp.Value; + _logger.Debug("注入额外图像: {Key} | Injected additional image: {Key}", kvp.Key); + } + } + } + + /// + /// 注入配置中的 Logo 和公司信息 | Inject logo and company info from config + /// + private void InjectConfigData(ReportContext context) + { + // 注入公司名称 | Inject company name + if (!string.IsNullOrEmpty(_reportConfig.CompanyName)) + { + context.Properties["CompanyName"] = _reportConfig.CompanyName; + } + + // 注入软件名称 | Inject software name + if (!string.IsNullOrEmpty(_reportConfig.SoftwareName)) + { + context.Properties["SoftwareName"] = _reportConfig.SoftwareName; + } + + // 注入公司 Logo | Inject company logo + if (!string.IsNullOrEmpty(_reportConfig.CompanyLogo)) + { + var logoPath = Path.IsPathRooted(_reportConfig.CompanyLogo) + ? _reportConfig.CompanyLogo + : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _reportConfig.CompanyLogo); + + if (File.Exists(logoPath)) + { + context.Images["companyLogo"] = new ImageData + { + SourceType = ImageSourceType.FilePath, + FilePath = logoPath + }; + _logger.Info("公司 Logo 已加载: {Path} | Company logo loaded: {Path}", logoPath); + } + else + { + _logger.Warn("公司 Logo 文件不存在: {Path} | Company logo file not found: {Path}", logoPath); + } + } + + // 注入软件 Logo | Inject software logo + if (!string.IsNullOrEmpty(_reportConfig.SoftwareLogo)) + { + var softwareLogoPath = Path.IsPathRooted(_reportConfig.SoftwareLogo) + ? _reportConfig.SoftwareLogo + : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _reportConfig.SoftwareLogo); + + if (File.Exists(softwareLogoPath)) + { + context.Images["softwareLogo"] = new ImageData + { + SourceType = ImageSourceType.FilePath, + FilePath = softwareLogoPath + }; + _logger.Info("软件 Logo 已加载: {Path} | Software logo loaded: {Path}", softwareLogoPath); + } + else + { + _logger.Warn("软件 Logo 文件不存在: {Path} | Software logo file not found: {Path}", softwareLogoPath); + } + } + } + + /// + /// 注入自定义属性 | Inject custom properties + /// + private void InjectCustomProperties(ReportContext context, ReportRequest request) + { + if (request.CustomProperties == null || request.CustomProperties.Count == 0) + return; + + foreach (var kvp in request.CustomProperties) + { + context.Properties[kvp.Key] = kvp.Value; + } + } + + /// + /// 根据 ReportContext 中的结果分组生成首页汇总表数据 + /// Generate homepage summary table data from ReportContext result groups + /// + private List> CreateSummaryTableData(ReportContext context) + { + var rows = new List>(); + + foreach (var group in context.ResultGroups) + { + var inspectionType = group.ProcessorType switch + { + "LineMeasurementProcessor" => "线测量 | Line Measurement", + "BgaVoidRateProcessor" => "BGA 气泡率检测 | BGA Void Rate", + "VoidMeasurementProcessor" => "空隙测量 | Void Measurement", + "FillRateProcessor" => "通孔填锡率 | Via Fill Rate", + _ => group.ProcessorType + }; + + var classification = string.IsNullOrEmpty(group.Classification) ? "N/A" : group.Classification; + var status = classification == "Pass" ? "[PASS] 合格" : classification == "Fail" ? "[FAIL] 不合格" : "—"; + + rows.Add(new Dictionary + { + ["inspectionType"] = inspectionType, + ["classification"] = classification, + ["status"] = status + }); + } + + return rows; + } + + #endregion + } +} diff --git a/XP.ReportEngine/Templates/StandardReportTemplate.json b/XP.ReportEngine/Templates/StandardReportTemplate.json new file mode 100644 index 0000000..64fb759 --- /dev/null +++ b/XP.ReportEngine/Templates/StandardReportTemplate.json @@ -0,0 +1,222 @@ +{ + "document": { + "pageSize": "A4", + "orientation": "Portrait", + "margins": { "top": 40, "bottom": 20, "left": 20, "right": 20 }, + "header": { + "enabled": true, + "left": [ + "${loc:Report_Title}", + "${loc:Report_Id}:${metadata.reportId} | ${loc:Report_Date}:${formatDate(metadata.inspectionDate)} | ${loc:Report_Sample}:${metadata.sampleName}" + ], + "rightImageKey": "companyLogo", + "fontSize": 7, + "color": "#666666", + "showLine": true + }, + "footer": { + "enabled": true, + "left": ["${CompanyName}"], + "right": ["{currentPage} / {totalPages}"], + "fontSize": 8, + "color": "#666666", + "showLine": true + } + }, + "pages": [ + { + "type": "homepage", + "elements": [ + { + "type": "row", "size": [170, 40], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "companyLogo", "size": [50, 30], "align": "left" }, + { "type": "text", "content": "${CompanyName}", "style": "companyName", "align": "left" } + ] + }, + { + "type": "column", "align": "right", + "children": [ + { "type": "image", "dataKey": "softwareLogo", "size": [15, 20], "align": "right" }, + { "type": "text", "content": "${SoftwareName}", "style": "companyName", "align": "right" } + ] + } + ] + }, + { "type": "spacer", "size": [170, 15], "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Title}", "style": "title", "positioning": "flow" }, + { "type": "spacer", "size": [170, 10], "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Id}:${metadata.reportId}", "style": "homepageInfo", "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Sample}:${metadata.sampleName}", "style": "homepageInfo", "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Description}:${metadata.description}", "style": "homepageInfo", "positioning": "flow" }, + { "type": "image", "dataKey": "workpieceImage", "size": [160, 110], "border": true, "align": "center", "style": "imageDefault", "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Operator}:${metadata.operatorName}", "style": "homepageFooter", "positioning": "flow" }, + { "type": "text", "content": "${loc:Report_Date}:${formatDate(metadata.inspectionDate)}", "style": "homepageFooter", "positioning": "flow" } + ] + }, + { + "type": "summary", + "elements": [ + { "type": "text", "content": "${loc:Report_Summary}", "style": "homepageHeading", "positioning": "flow" }, + { + "type": "table", "dataKey": "summaryTable", "positioning": "flow", "size": [170, 0], "style": "tableDefault", + "columns": [ + { "header": "${loc:Field_InspectionType}", "field": "inspectionType", "width": 50, "align": "left" }, + { "header": "${loc:Field_Result}", "field": "classification", "width": 30, "align": "center", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } }, + { "header": "${loc:Field_Status}", "field": "status", "width": 30, "align": "center", "colorRules": { "合格": "#008000", "PASS": "#008000", "不合格": "#FF0000", "FAIL": "#FF0000" } } + ] + } + ] + }, + { + "type": "metricData", + "elements": [ + { "type": "text", "content": "${loc:Page_MetricData}", "style": "heading", "positioning": "flow" }, + { + "type": "row", "size": [170, 100], "widths": [6, 4], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "lineMeasurementImage", "size": [110, 90], "border": true, "align": "left" } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "${loc:Measurement_Type}:${measurementType}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Field_Point1}:${point1}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Field_Point2}:${point2}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_Distance}:${actualDistance} ${unit}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_Angle}:${angle}°", "style": "body", "align": "left" } + ] + } + ] + } + ] + }, + { + "type": "bgaInspection", + "elements": [ + { "type": "text", "content": "${loc:Page_BgaInspection}", "style": "heading", "positioning": "flow" }, + { + "type": "row", "size": [170, 100], "widths": [6, 4], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "bgaInspectionImage", "size": [110, 90], "border": true, "align": "left" } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "${loc:Bga_Count}:${bgaCount}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_VoidRate}:${formatPercent(voidRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_FillRate}:${formatPercent(fillRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Bga_TotalArea}:${formatNumber(totalBgaArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Bga_TotalVoidArea}:${formatNumber(totalVoidArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Bga_VoidLimit}:${formatPercent(voidLimit)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Table_Classification}:${classification}", "style": "conclusion", "align": "left", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } } + ] + } + ] + }, + { + "type": "table", "dataKey": "bgaBallsTable", "positioning": "flow", "size": [170, 0], "style": "tableDefault", + "columns": [ + { "header": "${loc:Bga_BallIndex}", "field": "index", "width": 25, "align": "center" }, + { "header": "${loc:Table_VoidRate}", "field": "voidRate", "width": 40, "align": "center" }, + { "header": "${loc:Table_Area}", "field": "area", "width": 40, "align": "center" }, + { "header": "${loc:Table_Classification}", "field": "classification", "width": 35, "align": "center", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } } + ] + } + ] + }, + { + "type": "voidInspection", + "elements": [ + { "type": "text", "content": "${loc:Page_VoidInspection}", "style": "heading", "positioning": "flow" }, + { + "type": "row", "size": [170, 100], "widths": [6, 4], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "voidInspectionImage", "size": [110, 90], "border": true, "align": "left" } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "${loc:Void_RoiArea}:${formatNumber(roiArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Void_TotalArea}:${formatNumber(totalVoidArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_VoidRate}:${formatPercent(voidRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Void_Limit}:${formatPercent(voidLimit)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Void_Count}:${voidCount}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Void_MaxArea}:${formatNumber(maxVoidArea, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Table_Classification}:${classification}", "style": "conclusion", "align": "left", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } } + ] + } + ] + }, + { + "type": "table", "dataKey": "voidsTable", "positioning": "flow", "size": [170, 0], "style": "tableDefault", + "columns": [ + { "header": "${loc:Table_Index}", "field": "index", "width": 20, "align": "center" }, + { "header": "${loc:Table_Area}", "field": "area", "width": 35, "align": "center" }, + { "header": "${loc:Table_AreaPercent}", "field": "areaPercent", "width": 35, "align": "center" }, + { "header": "${loc:Table_CenterX}", "field": "centerX", "width": 30, "align": "center" }, + { "header": "${loc:Table_CenterY}", "field": "centerY", "width": 30, "align": "center" } + ] + } + ] + }, + { + "type": "viaFillInspection", + "elements": [ + { "type": "text", "content": "${loc:Page_ViaFillInspection}", "style": "heading", "positioning": "flow" }, + { + "type": "row", "size": [170, 100], "widths": [6, 4], "positioning": "flow", + "children": [ + { + "type": "column", "align": "left", + "children": [ + { "type": "image", "dataKey": "viaFillImage", "size": [110, 90], "border": true, "align": "left" } + ] + }, + { + "type": "column", "align": "left", + "children": [ + { "type": "text", "content": "${loc:Fill_Rate}:${formatPercent(fillRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Measurement_VoidRate}:${formatPercent(voidRate)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Fill_FullDistance}:${formatNumber(fullDistance, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Fill_FillDistance}:${formatNumber(fillDistance, 2)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Fill_THTLimit}:${formatPercent(thtLimit)}", "style": "body", "align": "left" }, + { "type": "text", "content": "${loc:Table_Classification}:${classification}", "style": "conclusion", "align": "left", "colorRules": { "Pass": "#008000", "Fail": "#FF0000" } } + ] + } + ] + } + ] + } + ], + "styles": { + "title": { "font": "auto", "size": 28, "bold": true, "italic": false, "color": "#1a1a1a", "align": "center" }, + "companyName": { "font": "auto", "size": 10, "bold": false, "italic": false, "color": "#333333", "align": "center" }, + "homepageInfo": { "font": "auto", "size": 12, "bold": false, "italic": false, "color": "#333333", "align": "left", "paddingLeft": 10 }, + "homepageFooter": { "font": "auto", "size": 12, "bold": false, "italic": false, "color": "#333333", "align": "center" }, + "homepageHeading": { "font": "auto", "size": 14, "bold": true, "italic": false, "color": "#333333", "align": "left" }, + "heading": { "font": "auto", "size": 16, "bold": true, "italic": false, "color": "#333333", "align": "left", "marginBottom": 3 }, + "body": { "font": "auto", "size": 11, "bold": false, "italic": false, "color": "#333333", "align": "left" }, + "bodyBold": { "font": "auto", "size": 11, "bold": true, "italic": false, "color": "#1a1a1a", "align": "left" }, + "conclusion": { "font": "auto", "size": 12, "bold": true, "italic": false, "color": "#333333", "align": "left", "marginTop": 3 }, + "imageDefault": { "font": "auto", "size": 12, "bold": false, "italic": false, "color": "#333333", "align": "center", "marginTop": 5, "marginBottom": 5 }, + "tableHeader": { "font": "auto", "size": 10, "bold": true, "italic": false, "color": "#ffffff", "align": "center", "backgroundColor": "#4472C4" }, + "tableDefault": { "font": "auto", "size": 10, "bold": false, "italic": false, "color": "#333333", "align": "center", "marginTop": 5 }, + "tableCell": { "font": "auto", "size": 10, "bold": false, "italic": false, "color": "#333333", "align": "center" } + } +} diff --git a/XP.ReportEngine/ViewModels/ReportDemoViewModel.cs b/XP.ReportEngine/ViewModels/ReportDemoViewModel.cs new file mode 100644 index 0000000..f7d75b6 --- /dev/null +++ b/XP.ReportEngine/ViewModels/ReportDemoViewModel.cs @@ -0,0 +1,618 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Windows; +using Prism.Commands; +using Prism.Mvvm; +using XP.Common.GeneralForm.Views; +using XP.Common.Logging.Interfaces; +using XP.Common.PdfViewer.Interfaces; +using XP.ReportEngine.Configs; +using XP.ReportEngine.Interfaces; +using XP.ReportEngine.Models; +using XP.ReportEngine.Services; + +namespace XP.ReportEngine.ViewModels +{ + /// + /// 报告生成演示窗口 ViewModel | Report generation demo window ViewModel + /// 演示如何使用 IReportService 生成 PDF 报告 + /// Demonstrates how to use IReportService to generate PDF reports + /// + public class ReportDemoViewModel : BindableBase + { + private readonly IReportService _reportService; + private readonly IPdfViewerService _pdfViewerService; + private readonly IPdfPrintService _pdfPrintService; + private readonly ILoggerService _logger; + private readonly ReportIdGenerator _reportIdGenerator; + private readonly ReportConfig _reportConfig; + + private string _productName = "PCB-TEST-001"; + private string _operatorName = "戚明轩 mingxuan.qi@hexagon.com"; + private string _description = "BGA 焊球气泡率检测"; + private string _cncProgram = "Prog001"; + private string _productCode = "PCBA-X100"; + private string _workpieceSN = "SN20250001"; + private string _deviceId = "XP-CT-001"; + private string _machineId = "MC01"; + private string _statusMessage = "就绪"; + private string _lastOutputPath; + private bool _isGenerating; + + #region 属性 | Properties + + /// + /// 产品名称 | Product name + /// + public string ProductName + { + get => _productName; + set => SetProperty(ref _productName, value); + } + + /// + /// 操作员 | Operator + /// + public string OperatorName + { + get => _operatorName; + set => SetProperty(ref _operatorName, value); + } + + /// + /// 描述 | Description + /// + public string Description + { + get => _description; + set => SetProperty(ref _description, value); + } + + /// + /// CNC 程序名称 | CNC program name + /// + public string CncProgram + { + get => _cncProgram; + set => SetProperty(ref _cncProgram, value); + } + + /// + /// 产品类型码 | Product type code + /// + public string ProductCode + { + get => _productCode; + set => SetProperty(ref _productCode, value); + } + + /// + /// 工件 SN 码 | Workpiece serial number + /// + public string WorkpieceSN + { + get => _workpieceSN; + set => SetProperty(ref _workpieceSN, value); + } + + /// + /// 检测设备编号 | Inspection device ID + /// + public string DeviceId + { + get => _deviceId; + set => SetProperty(ref _deviceId, value); + } + + /// + /// 生产机台号 | Production machine ID + /// + public string MachineId + { + get => _machineId; + set => SetProperty(ref _machineId, value); + } + + /// + /// 状态信息 | Status message + /// + public string StatusMessage + { + get => _statusMessage; + set => SetProperty(ref _statusMessage, value); + } + + /// + /// 是否正在生成 | Whether generating + /// + public bool IsGenerating + { + get => _isGenerating; + set + { + if (SetProperty(ref _isGenerating, value)) + { + GenerateReportCommand.RaiseCanExecuteChanged(); + OpenViewerCommand.RaiseCanExecuteChanged(); + PrintReportCommand.RaiseCanExecuteChanged(); + } + } + } + + #endregion + + #region 命令 | Commands + + /// + /// 生成报告命令 | Generate report command + /// + public DelegateCommand GenerateReportCommand { get; } + + /// + /// 打开 PDF 阅读器命令 | Open PDF viewer command + /// + public DelegateCommand OpenViewerCommand { get; } + + /// + /// 打印报告命令 | Print report command + /// + public DelegateCommand PrintReportCommand { get; } + + #endregion + + /// + /// 构造函数 | Constructor + /// + public ReportDemoViewModel( + IReportService reportService, + IPdfViewerService pdfViewerService, + IPdfPrintService pdfPrintService, + ILoggerService logger, + ReportIdGenerator reportIdGenerator, + ReportConfig reportConfig) + { + _reportService = reportService ?? throw new ArgumentNullException(nameof(reportService)); + _pdfViewerService = pdfViewerService ?? throw new ArgumentNullException(nameof(pdfViewerService)); + _pdfPrintService = pdfPrintService ?? throw new ArgumentNullException(nameof(pdfPrintService)); + _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); + _reportIdGenerator = reportIdGenerator ?? throw new ArgumentNullException(nameof(reportIdGenerator)); + _reportConfig = reportConfig ?? throw new ArgumentNullException(nameof(reportConfig)); + + GenerateReportCommand = new DelegateCommand(async () => await GenerateReportAsync(), () => !IsGenerating); + OpenViewerCommand = new DelegateCommand(OpenViewer, () => !IsGenerating && !string.IsNullOrEmpty(_lastOutputPath)); + PrintReportCommand = new DelegateCommand(PrintReport, () => !IsGenerating && !string.IsNullOrEmpty(_lastOutputPath)); + } + + /// + /// 生成报告(带进度条)| Generate report (with progress window) + /// + private async Task GenerateReportAsync() + { + IsGenerating = true; + StatusMessage = "正在生成报告..."; + + try + { + // 构建文件名占位符参数 | Build file name placeholder parameters + var fileNameParams = new Dictionary + { + ["ReportId"] = _reportIdGenerator.GenerateNext(), + ["ProductName"] = ProductName, + ["CncProgram"] = CncProgram, + ["ProductCode"] = ProductCode, + ["WorkpieceSN"] = WorkpieceSN, + ["DeviceId"] = DeviceId, + ["MachineId"] = MachineId, + ["Result"] = "Pass" + }; + + // 确定输出路径:提示用户是否使用默认位置 | Determine output path: ask user whether to use default location + var defaultOutputPath = _reportConfig.ResolveOutputFilePath(fileNameParams); + var defaultFileName = System.IO.Path.GetFileName(defaultOutputPath); + + var result = MessageBox.Show( + $"是否将报告输出到默认位置?\r\n{defaultOutputPath}", + "输出位置确认", + MessageBoxButton.YesNoCancel, + MessageBoxImage.Question); + + if (result == MessageBoxResult.Cancel) + { + StatusMessage = "已取消生成"; + IsGenerating = false; + return; + } + + string outputPath; + if (result == MessageBoxResult.No) + { + // 用户选择自定义位置 | User chooses custom location + var saveDialog = new Microsoft.Win32.SaveFileDialog + { + Title = "选择报告保存位置", + Filter = "PDF 文件 (*.pdf)|*.pdf", + FileName = defaultFileName, + DefaultExt = ".pdf", + InitialDirectory = System.IO.Path.GetDirectoryName(defaultOutputPath) + }; + + if (saveDialog.ShowDialog() != true) + { + StatusMessage = "已取消生成"; + IsGenerating = false; + return; + } + + outputPath = saveDialog.FileName; + } + else + { + // 使用默认路径 | Use default path + outputPath = defaultOutputPath; + } + + // 创建进度条窗口 | Create progress window + var progressWindow = new ProgressWindow( + title: "报告生成中", + message: "正在准备数据...", + isCancelable: false, + logger: _logger); + + progressWindow.Owner = Application.Current.MainWindow; + progressWindow.Show(); + + try + { + // 步骤 1:准备模拟数据 | Step 1: Prepare mock data + progressWindow.UpdateProgress("正在准备检测数据...", 10); + await Task.Delay(300); // 模拟耗时 | Simulate delay + + var processorOutputs = CreateMockProcessorOutputs(); + + // 步骤 2:构建报告请求 | Step 2: Build report request + progressWindow.UpdateProgress("正在组装报告数据...", 30); + await Task.Delay(200); + + var request = new ReportRequest + { + ProcessorOutputs = processorOutputs, + Metadata = new ReportMetadata + { + ReportId = fileNameParams["ReportId"], + InspectionDate = DateTime.Now, + SampleName = ProductName, + OperatorName = OperatorName, + Description = Description + }, + OutputFilePath = outputPath, + FileNameParameters = fileNameParams + }; + + // 注入工件整体图片 | Inject workpiece overview image + var workpieceImagePath = System.IO.Path.Combine(MockImageDirectory, "OverView.png"); + if (File.Exists(workpieceImagePath)) + { + request.AdditionalImages["workpieceImage"] = new ImageData + { + SourceType = ImageSourceType.FilePath, + FilePath = workpieceImagePath + }; + } + + // 步骤 3:调用报告服务生成(在后台线程执行,避免阻塞 UI) + // Step 3: Call report service (on background thread to avoid blocking UI) + progressWindow.UpdateProgress("正在生成 PDF...", 60); + await Task.Delay(200); + + var genResult = await Task.Run(() => _reportService.GenerateAsync(request)); + + // 步骤 4:处理结果 | Step 4: Handle result + progressWindow.UpdateProgress("正在完成...", 95); + await Task.Delay(200); + + if (genResult.IsSuccess) + { + _lastOutputPath = genResult.OutputFilePath; + StatusMessage = $"报告生成成功:{genResult.OutputFilePath}"; + _logger.Info("报告生成成功:{Path} | Report generated successfully: {Path}", genResult.OutputFilePath); + + progressWindow.UpdateProgress("报告生成完成!", 100); + await Task.Delay(500); + + // 根据配置自动打开 PDF 阅读器 | Auto-open PDF viewer based on config + if (_reportConfig.AutoOpenAfterGenerate) + { + try + { + _pdfViewerService.OpenViewer(genResult.OutputFilePath); + } + catch (Exception viewerEx) + { + _logger.Warn("自动打开 PDF 失败 | Auto-open PDF failed: {Message}", viewerEx.Message); + } + } + } + else + { + StatusMessage = $"报告生成失败:{genResult.ErrorMessage}"; + _logger.Error(null, "报告生成失败:{Message} | Report generation failed: {Message}", genResult.ErrorMessage); + + MessageBox.Show( + $"报告生成失败:\n{genResult.ErrorMessage}", + "错误", + MessageBoxButton.OK, + MessageBoxImage.Error); + } + } + finally + { + progressWindow.Close(); + } + } + catch (Exception ex) + { + StatusMessage = $"报告生成异常:{ex.Message}"; + _logger.Error(ex, "报告生成异常 | Report generation exception: {Message}", ex.Message); + + MessageBox.Show( + $"报告生成过程中发生异常:\n{ex.Message}", + "错误", + MessageBoxButton.OK, + MessageBoxImage.Error); + } + finally + { + IsGenerating = false; + OpenViewerCommand.RaiseCanExecuteChanged(); + PrintReportCommand.RaiseCanExecuteChanged(); + } + } + + /// + /// 打开 PDF 阅读器 | Open PDF viewer + /// + private void OpenViewer() + { + if (string.IsNullOrEmpty(_lastOutputPath) || !File.Exists(_lastOutputPath)) + { + MessageBox.Show("PDF 文件不存在,请先生成报告。", "提示", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + try + { + // 使用 XP.Common PDF 阅读器打开 | Open with XP.Common PDF viewer + _pdfViewerService.OpenViewer(_lastOutputPath); + _logger.Info("使用内置 PDF 阅读器打开:{Path} | Opened with built-in PDF viewer: {Path}", _lastOutputPath); + } + catch (Exception ex) + { + _logger.Error(ex, "打开 PDF 失败 | Failed to open PDF: {Message}", ex.Message); + MessageBox.Show($"打开 PDF 失败:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + /// + /// 打印报告 | Print report + /// + private void PrintReport() + { + if (string.IsNullOrEmpty(_lastOutputPath) || !File.Exists(_lastOutputPath)) + { + MessageBox.Show("PDF 文件不存在,请先生成报告。", "提示", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + try + { + var confirmed = _pdfPrintService.PrintWithDialog(_lastOutputPath); + if (confirmed) + { + _logger.Info("报告已发送到打印机:{Path} | Report sent to printer: {Path}", _lastOutputPath); + StatusMessage = "报告已发送到打印机"; + } + } + catch (Exception ex) + { + _logger.Error(ex, "打印报告失败 | Failed to print report: {Message}", ex.Message); + MessageBox.Show($"打印失败:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + #region 模拟数据 | Mock Data + + /// + /// 模拟图像目录路径 | Mock image directory path + /// + private const string MockImageDirectory = @"D:\XplorePlane\DetectorImages"; + + /// + /// 创建模拟处理器输出数据(演示用,覆盖所有检测类型) + /// Create mock processor outputs (for demo, covers all inspection types) + /// + private List CreateMockProcessorOutputs() + { + return new List + { + CreateLineMeasurementOutput(), + CreateBgaVoidRateOutput(), + CreateVoidMeasurementOutput(), + CreateFillRateOutput() + }; + } + + /// + /// 创建线测量处理器模拟数据 | Create line measurement processor mock data + /// + private ProcessorOutput CreateLineMeasurementOutput() + { + return new ProcessorOutput + { + ProcessorType = "LineMeasurementProcessor", + OutputData = new Dictionary + { + ["MeasurementType"] = "TwoPointDistance", + ["Point1"] = "X=125.32, Y=80.15", + ["Point2"] = "X=340.78, Y=80.15", + ["PixelDistance"] = 215.46, + ["ActualDistance"] = 3.256, + ["Unit"] = "mm", + ["Angle"] = 0.0 + }, + AnnotatedImage = LoadMockImage("BGA.png") + }; + } + + /// + /// 创建 BGA 气泡率处理器模拟数据 | Create BGA void rate processor mock data + /// + private ProcessorOutput CreateBgaVoidRateOutput() + { + // 生成 64 组 BGA 球模拟数据 | Generate 64 BGA ball mock data + var bgaBalls = new List>(); + var random = new Random(42); // 固定种子确保可重复 | Fixed seed for reproducibility + var voidLimit = 0.05; + + for (int i = 1; i <= 64; i++) + { + // 大部分合格,少数不合格 | Most pass, a few fail + double voidRate; + if (i == 12 || i == 27 || i == 41 || i == 58) + { + // 这几个球不合格 | These balls fail + voidRate = Math.Round(0.05 + random.NextDouble() * 0.03, 4); + } + else + { + voidRate = Math.Round(random.NextDouble() * 0.045, 4); + } + + var area = Math.Round(190.0 + random.NextDouble() * 15.0, 1); + var classification = voidRate > voidLimit ? "Fail" : "Pass"; + + bgaBalls.Add(new Dictionary + { + ["Index"] = i, + ["VoidRate"] = voidRate, + ["Area"] = area, + ["Classification"] = classification + }); + } + + return new ProcessorOutput + { + ProcessorType = "BgaVoidRateProcessor", + OutputData = new Dictionary + { + ["BgaCount"] = 64, + ["VoidRate"] = 0.028, + ["FillRate"] = 0.972, + ["TotalBgaArea"] = 12500.5, + ["TotalVoidArea"] = 350.2, + ["Classification"] = "Pass", + ["VoidLimit"] = 0.05, + ["BgaBalls"] = bgaBalls + }, + AnnotatedImage = LoadMockImage("BGA.png") + }; + } + + /// + /// 创建空隙测量处理器模拟数据 | Create void measurement processor mock data + /// + private ProcessorOutput CreateVoidMeasurementOutput() + { + return new ProcessorOutput + { + ProcessorType = "VoidMeasurementProcessor", + OutputData = new Dictionary + { + ["RoiArea"] = 5000.0, + ["TotalVoidArea"] = 125.8, + ["VoidRate"] = 0.025, + ["VoidLimit"] = 0.05, + ["VoidCount"] = 5, + ["MaxVoidArea"] = 65.2, + ["Classification"] = "Pass", + ["Voids"] = new List> + { + new() { ["Index"] = 1, ["Area"] = 65.2, ["AreaPercent"] = 1.30, ["CenterX"] = 120.5, ["CenterY"] = 85.3 }, + new() { ["Index"] = 2, ["Area"] = 38.4, ["AreaPercent"] = 0.77, ["CenterX"] = 200.1, ["CenterY"] = 150.8 }, + new() { ["Index"] = 3, ["Area"] = 22.2, ["AreaPercent"] = 0.44, ["CenterX"] = 80.0, ["CenterY"] = 220.5 }, + new() { ["Index"] = 4, ["Area"] = 15.6, ["AreaPercent"] = 0.31, ["CenterX"] = 310.2, ["CenterY"] = 95.7 }, + new() { ["Index"] = 5, ["Area"] = 8.9, ["AreaPercent"] = 0.18, ["CenterX"] = 155.8, ["CenterY"] = 280.1 } + } + }, + AnnotatedImage = LoadMockImage("Void.png") + }; + } + + /// + /// 创建通孔填锡率处理器模拟数据 | Create via fill rate processor mock data + /// + private ProcessorOutput CreateFillRateOutput() + { + return new ProcessorOutput + { + ProcessorType = "FillRateProcessor", + OutputData = new Dictionary + { + ["FillRate"] = 0.85, + ["VoidRate"] = 0.15, + ["FullDistance"] = 1.60, + ["FillDistance"] = 1.36, + ["THTLimit"] = 0.75, + ["Classification"] = "Pass", + ["E1"] = new Dictionary + { + ["CenterX"] = 256.0, ["CenterY"] = 256.0, + ["SemiAxisA"] = 120.5, ["SemiAxisB"] = 118.2, ["Angle"] = 2.3 + }, + ["E2"] = new Dictionary + { + ["CenterX"] = 256.0, ["CenterY"] = 256.0, + ["SemiAxisA"] = 95.8, ["SemiAxisB"] = 93.1, ["Angle"] = 2.3 + }, + ["E3"] = new Dictionary + { + ["CenterX"] = 256.0, ["CenterY"] = 256.0, + ["SemiAxisA"] = 70.2, ["SemiAxisB"] = 68.5, ["Angle"] = 1.8 + }, + ["E4"] = new Dictionary + { + ["CenterX"] = 256.0, ["CenterY"] = 256.0, + ["SemiAxisA"] = 45.0, ["SemiAxisB"] = 43.7, ["Angle"] = 1.5 + } + }, + AnnotatedImage = LoadMockImage("Void.png") + }; + } + + /// + /// 加载模拟图像文件 | Load mock image file + /// 从指定目录加载图像,文件不存在时返回 null + /// Loads image from specified directory, returns null if file not found + /// + /// 图像文件名 | Image file name + /// 图像数据对象或 null | ImageData object or null + private ImageData LoadMockImage(string fileName) + { + var filePath = System.IO.Path.Combine(MockImageDirectory, fileName); + if (!File.Exists(filePath)) + { + _logger.Warn("模拟图像文件不存在:{Path} | Mock image file not found: {Path}", filePath); + return null; + } + + return new ImageData + { + SourceType = ImageSourceType.FilePath, + FilePath = filePath + }; + } + + #endregion + } +} diff --git a/XP.ReportEngine/Views/ReportDemoWindow.xaml b/XP.ReportEngine/Views/ReportDemoWindow.xaml new file mode 100644 index 0000000..8c28b9e --- /dev/null +++ b/XP.ReportEngine/Views/ReportDemoWindow.xaml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XP.ReportEngine/Views/ReportDemoWindow.xaml.cs b/XP.ReportEngine/Views/ReportDemoWindow.xaml.cs new file mode 100644 index 0000000..ed60a62 --- /dev/null +++ b/XP.ReportEngine/Views/ReportDemoWindow.xaml.cs @@ -0,0 +1,21 @@ +using System.Windows; +using XP.ReportEngine.ViewModels; + +namespace XP.ReportEngine.Views +{ + /// + /// 报告生成演示窗口 | Report generation demo window + /// + public partial class ReportDemoWindow : Window + { + /// + /// 构造函数(通过 DI 注入 ViewModel)| Constructor (ViewModel injected via DI) + /// + /// 报告演示 ViewModel | Report demo ViewModel + public ReportDemoWindow(ReportDemoViewModel viewModel) + { + InitializeComponent(); + DataContext = viewModel; + } + } +} diff --git a/XP.ReportEngine/XP.ReportEngine.csproj b/XP.ReportEngine/XP.ReportEngine.csproj new file mode 100644 index 0000000..540ffef --- /dev/null +++ b/XP.ReportEngine/XP.ReportEngine.csproj @@ -0,0 +1,37 @@ + + + net8.0-windows7.0 + true + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + diff --git a/XplorePlane.sln b/XplorePlane.sln index baf9467..4000462 100644 --- a/XplorePlane.sln +++ b/XplorePlane.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.14.36811.4 +VisualStudioVersion = 17.14.37203.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XplorePlane", "XplorePlane\XplorePlane.csproj", "{07978DB9-4B88-4F42-9054-73992742BD6A}" EndProject @@ -66,6 +66,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XP.Calibration", "XP.Calibr EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XP.Calibration", "XP.Calibration", "{D4E5F6A7-B8C9-0123-4567-89ABCDEF0123}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XP.ReportEngine", "XP.ReportEngine\XP.ReportEngine.csproj", "{809A8588-F64C-4738-8827-CFBC59943DBF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -263,6 +265,18 @@ Global {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|Any CPU {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|x64.ActiveCfg = Debug|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|x64.Build.0 = Debug|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|x86.ActiveCfg = Debug|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|x86.Build.0 = Debug|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Release|Any CPU.Build.0 = Release|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Release|x64.ActiveCfg = Release|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Release|x64.Build.0 = Release|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Release|x86.ActiveCfg = Release|Any CPU + {809A8588-F64C-4738-8827-CFBC59943DBF}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/XplorePlane/App.config b/XplorePlane/App.config index cbab03a..3428b03 100644 --- a/XplorePlane/App.config +++ b/XplorePlane/App.config @@ -8,7 +8,9 @@ - + + + @@ -128,7 +130,6 @@ - @@ -154,7 +155,7 @@ - + @@ -167,6 +168,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XplorePlane/App.xaml.cs b/XplorePlane/App.xaml.cs index 741bc46..0d0b6d7 100644 --- a/XplorePlane/App.xaml.cs +++ b/XplorePlane/App.xaml.cs @@ -28,10 +28,15 @@ using XP.Common.Logging.Interfaces; using XP.Common.Module; using XP.Hardware.Detector.Module; using XP.Hardware.Detector.Services; +using XP.Hardware.Detector.Services; using XP.Hardware.MotionControl.Module; +using XP.Hardware.Plc.Abstractions; using XP.Hardware.PLC; +using XP.Hardware.PLC.Abstractions; +using XP.Hardware.PLC.Services; using XP.Hardware.RaySource.Module; using XP.Hardware.RaySource.Services; +using XP.ReportEngine; using XplorePlane.Services; using XplorePlane.Services.AppState; using XplorePlane.Services.Camera; @@ -222,6 +227,38 @@ namespace XplorePlane Log.Error(ex, "数据库资源释放失败,忽略该错误继续退出 | Database resource release failed, ignoring error and continuing exit"); } + // 释放 PLC 资源 + try + { + var bootstrapper = AppBootstrapper.Instance; + if (bootstrapper != null) + { + var plcService = bootstrapper.Container.Resolve(); + plcService?.Dispose(); + Log.Information("PLC 资源已释放"); + } + } + catch (Exception ex) + { + Log.Error(ex, "PLC 资源释放失败"); + } + + // 释放探测器资源 + try + { + var bootstrapper = AppBootstrapper.Instance; + if (bootstrapper != null) + { + var detectorService = bootstrapper.Container.Resolve(); + detectorService?.Dispose(); + Log.Information("探测器资源已释放"); + } + } + catch (Exception ex) + { + Log.Error(ex, "探测器资源释放失败"); + } + // 释放录制服务资源 try { @@ -237,7 +274,6 @@ namespace XplorePlane { Log.Error(ex, "录制服务资源释放失败"); } - Log.CloseAndFlush(); base.OnExit(e); } @@ -515,6 +551,7 @@ namespace XplorePlane moduleCatalog.AddModule(); moduleCatalog.AddModule(); moduleCatalog.AddModule(); + moduleCatalog.AddModule(); base.ConfigureModuleCatalog(moduleCatalog); } diff --git a/XplorePlane/Assets/Icons/NoCamera.png b/XplorePlane/Assets/Icons/NoCamera.png new file mode 100644 index 0000000..db2793f Binary files /dev/null and b/XplorePlane/Assets/Icons/NoCamera.png differ diff --git a/XplorePlane/Assets/Icons/Scale.png b/XplorePlane/Assets/Icons/Scale.png new file mode 100644 index 0000000..6c4b3f0 Binary files /dev/null and b/XplorePlane/Assets/Icons/Scale.png differ diff --git a/XplorePlane/Assets/Icons/circle32.png b/XplorePlane/Assets/Icons/circle32.png new file mode 100644 index 0000000..88c1158 Binary files /dev/null and b/XplorePlane/Assets/Icons/circle32.png differ diff --git a/XplorePlane/Services/Cnc/CncExecutionService.cs b/XplorePlane/Services/Cnc/CncExecutionService.cs index 4e247bb..904be67 100644 --- a/XplorePlane/Services/Cnc/CncExecutionService.cs +++ b/XplorePlane/Services/Cnc/CncExecutionService.cs @@ -701,8 +701,9 @@ namespace XplorePlane.Services.Cnc try { var pipelineNodes = BuildPipelineNodeViewModels(inspectionNode.Pipeline); - resultImage = await _pipelineExecutionService.ExecutePipelineAsync( + var execResult = await _pipelineExecutionService.ExecutePipelineAsync( pipelineNodes, sourceImage, null, cancellationToken); + resultImage = execResult.Image; if (resultImage != null) { diff --git a/XplorePlane/Services/ImageProcessing/IImageProcessingService.cs b/XplorePlane/Services/ImageProcessing/IImageProcessingService.cs index e9160b6..d93f773 100644 --- a/XplorePlane/Services/ImageProcessing/IImageProcessingService.cs +++ b/XplorePlane/Services/ImageProcessing/IImageProcessingService.cs @@ -25,5 +25,15 @@ namespace XplorePlane.Services IDictionary parameters, IProgress progress = null, CancellationToken cancellationToken = default); + + /// + /// 执行单算子并返回输出图像与算子 快照(浅拷贝)。 + /// + Task<(BitmapSource image, IReadOnlyDictionary outputData)> ProcessImageWithOutputAsync( + BitmapSource source, + string processorName, + IDictionary parameters, + IProgress progress = null, + CancellationToken cancellationToken = default); } } \ No newline at end of file diff --git a/XplorePlane/Services/ImageProcessing/ImageConverter.cs b/XplorePlane/Services/ImageProcessing/ImageConverter.cs index 539e7d1..ce28cfd 100644 --- a/XplorePlane/Services/ImageProcessing/ImageConverter.cs +++ b/XplorePlane/Services/ImageProcessing/ImageConverter.cs @@ -68,4 +68,4 @@ namespace XplorePlane.Services return BitmapSource.Create(width, height, 96, 96, PixelFormats.Gray8, null, pixels, stride); } } -} \ No newline at end of file +} diff --git a/XplorePlane/Services/ImageProcessing/ImageProcessingService.cs b/XplorePlane/Services/ImageProcessing/ImageProcessingService.cs index 7025567..177e30f 100644 --- a/XplorePlane/Services/ImageProcessing/ImageProcessingService.cs +++ b/XplorePlane/Services/ImageProcessing/ImageProcessingService.cs @@ -220,6 +220,18 @@ namespace XplorePlane.Services IDictionary parameters, IProgress progress = null, CancellationToken cancellationToken = default) + { + var (image, _) = await ProcessImageWithOutputAsync(source, processorName, parameters, progress, cancellationToken) + .ConfigureAwait(false); + return image; + } + + public async Task<(BitmapSource image, IReadOnlyDictionary outputData)> ProcessImageWithOutputAsync( + BitmapSource source, + string processorName, + IDictionary parameters, + IProgress progress = null, + CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -250,7 +262,11 @@ namespace XplorePlane.Services result.Freeze(); progress?.Report(1.0); - return result; + var snapshot = new Dictionary(processor.OutputData.Count); + foreach (var kv in processor.OutputData) + snapshot[kv.Key] = kv.Value; + + return (result, snapshot); } catch (OperationCanceledException) { @@ -265,7 +281,7 @@ namespace XplorePlane.Services _logger.Error(ex, "Image processing failed for processor: {ProcessorName}", processorName); throw new ImageProcessingException($"Image processing failed: {ex.Message}", ex); } - }, cancellationToken); + }, cancellationToken).ConfigureAwait(false); } public void Dispose() diff --git a/XplorePlane/Services/ImageProcessing/ProcessorUiMetadata.cs b/XplorePlane/Services/ImageProcessing/ProcessorUiMetadata.cs index 69b40c3..16235db 100644 --- a/XplorePlane/Services/ImageProcessing/ProcessorUiMetadata.cs +++ b/XplorePlane/Services/ImageProcessing/ProcessorUiMetadata.cs @@ -12,7 +12,8 @@ namespace XplorePlane.Services ("数学运算", "➗", 3), ("形态学处理", "⬚", 4), ("边缘检测", "📐", 5), - ("检测分析", "🔎", 6), + ("定位识别", "📌", 6), + ("检测分析", "🔎", 7), ("其他", "⚙", 99), }; @@ -34,6 +35,10 @@ namespace XplorePlane.Services "SubPixel", "SuperResolution", "HDR", "Effect", "PseudoColor", "Color")) return "图像增强"; + // 必须在 "Rotate" 之前:RotatedTemplateMatching 含子串 Rotate + if (ContainsAny(operatorKey, "RotatedTemplateMatching")) + return "定位识别"; + if (ContainsAny(operatorKey, "Mirror", "Rotate", "Grayscale", "Threshold")) return "图像变换"; @@ -107,6 +112,9 @@ namespace XplorePlane.Services return "🎞"; if (ContainsAny(operatorKey, "ColorLayer")) return "🧪"; + // 必须在 "Rotate" 之前:RotatedTemplateMatching 含子串 Rotate + if (ContainsAny(operatorKey, "RotatedTemplateMatching")) + return "🎯"; if (ContainsAny(operatorKey, "Mirror")) return "↔"; if (ContainsAny(operatorKey, "Rotate")) diff --git a/XplorePlane/Services/ImageProcessing/TemplateMatchOverlayRenderer.cs b/XplorePlane/Services/ImageProcessing/TemplateMatchOverlayRenderer.cs new file mode 100644 index 0000000..d9b9a14 --- /dev/null +++ b/XplorePlane/Services/ImageProcessing/TemplateMatchOverlayRenderer.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace XplorePlane.Services +{ + /// + /// 旋转模板匹配结果:在透明背景上绘制 1 像素绿色线框与中心十字,供 PolygonRoiCanvas 叠加层使用(与 BGA 工具分层方式一致)。 + /// + public static class TemplateMatchOverlayRenderer + { + public const string ProcessorKey = "RotatedTemplateMatching"; + private const int CrossHalfLength = 10; + + /// + /// 若最后一步为旋转模板匹配且需绘制、且有匹配,则复制一份 OutputData 供 UI 叠加层使用;否则返回 null。 + /// + public static Dictionary? TrySnapshotOutputForOverlay( + string operatorKey, + IReadOnlyDictionary parameters, + IReadOnlyDictionary outputData) + { + if (!string.Equals(operatorKey, ProcessorKey, StringComparison.OrdinalIgnoreCase)) + return null; + + if (!IsDrawResultsEnabled(parameters)) + return null; + + if (!TryGetMatchCount(outputData, out int c) || c <= 0) + return null; + + var copy = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var kv in outputData) + copy[kv.Key] = kv.Value; + return copy; + } + + /// + /// 生成与底图同尺寸的 Pbgra32 透明叠加图(仅绿色线)。 + /// + public static BitmapSource? CreateTransparentOverlay( + int pixelWidth, + int pixelHeight, + IReadOnlyDictionary? outputData) + { + if (pixelWidth <= 0 || pixelHeight <= 0 || outputData == null) + return null; + if (!TryGetMatchCount(outputData, out int count) || count <= 0) + return null; + + var green = new SolidColorBrush(Color.FromRgb(0, 255, 0)); + green.Freeze(); + var pen = new Pen(green, 1) + { + StartLineCap = PenLineCap.Flat, + EndLineCap = PenLineCap.Flat + }; + pen.Freeze(); + + var dv = new DrawingVisual(); + using (var dc = dv.RenderOpen()) + { + for (int i = 0; i < count; i++) + { + var pfx = count == 1 ? "" : $"[{i}]"; + if (!TryReadCorners(outputData, pfx, out var ltX, out var ltY, out var rtX, out var rtY, + out var rbX, out var rbY, out var lbX, out var lbY)) + continue; + + var lt = new Point(ltX, ltY); + var rt = new Point(rtX, rtY); + var rb = new Point(rbX, rbY); + var lb = new Point(lbX, lbY); + + dc.DrawLine(pen, lt, rt); + dc.DrawLine(pen, rt, rb); + dc.DrawLine(pen, rb, lb); + dc.DrawLine(pen, lb, lt); + + if (TryReadCenter(outputData, pfx, out var cx, out var cy)) + { + int h = CrossHalfLength; + dc.DrawLine(pen, new Point(cx - h, cy), new Point(cx + h, cy)); + dc.DrawLine(pen, new Point(cx, cy - h), new Point(cx, cy + h)); + } + } + } + + var rtb = new RenderTargetBitmap(pixelWidth, pixelHeight, 96, 96, PixelFormats.Pbgra32); + rtb.Render(dv); + rtb.Freeze(); + return rtb; + } + + private static bool IsDrawResultsEnabled(IReadOnlyDictionary parameters) + { + if (parameters == null || !parameters.TryGetValue("DrawResults", out var v)) + return true; + + if (v is bool b) + return b; + + try + { + return Convert.ToBoolean(v); + } + catch + { + return true; + } + } + + private static bool TryGetMatchCount(IReadOnlyDictionary d, out int count) + { + count = 0; + if (!d.TryGetValue("MatchCount", out var o) || o == null) + return false; + try + { + count = Convert.ToInt32(o); + return count > 0; + } + catch + { + return false; + } + } + + private static bool TryReadDouble(IReadOnlyDictionary d, string key, out double v) + { + v = default; + if (!d.TryGetValue(key, out var o) || o == null) + return false; + try + { + v = Convert.ToDouble(o); + return true; + } + catch + { + return false; + } + } + + private static bool TryReadCorners(IReadOnlyDictionary d, string pfx, + out double ltX, out double ltY, out double rtX, out double rtY, + out double rbX, out double rbY, out double lbX, out double lbY) + { + ltX = ltY = rtX = rtY = rbX = rbY = lbX = lbY = 0; + return TryReadDouble(d, "LtX" + pfx, out ltX) + && TryReadDouble(d, "LtY" + pfx, out ltY) + && TryReadDouble(d, "RtX" + pfx, out rtX) + && TryReadDouble(d, "RtY" + pfx, out rtY) + && TryReadDouble(d, "RbX" + pfx, out rbX) + && TryReadDouble(d, "RbY" + pfx, out rbY) + && TryReadDouble(d, "LbX" + pfx, out lbX) + && TryReadDouble(d, "LbY" + pfx, out lbY); + } + + private static bool TryReadCenter(IReadOnlyDictionary d, string pfx, out double cx, out double cy) + { + cx = cy = 0; + return TryReadDouble(d, "CenterX" + pfx, out cx) && TryReadDouble(d, "CenterY" + pfx, out cy); + } + } +} diff --git a/XplorePlane/Services/Pipeline/IPipelineExecutionService.cs b/XplorePlane/Services/Pipeline/IPipelineExecutionService.cs index 2ae801f..76d9825 100644 --- a/XplorePlane/Services/Pipeline/IPipelineExecutionService.cs +++ b/XplorePlane/Services/Pipeline/IPipelineExecutionService.cs @@ -9,9 +9,15 @@ namespace XplorePlane.Services { public record PipelineProgress(int CurrentStep, int TotalSteps, string CurrentOperator); + /// 流水线输出图像(始终为灰度预览路径下的结果)。 + /// 当且仅当最后一步为旋转模板匹配且需绘制匹配框时,为 OutputData 的副本,供 UI 透明叠加层使用;否则为 null。 + public sealed record PipelineExecutionResult( + BitmapSource Image, + IReadOnlyDictionary? TemplateMatchOverlayData); + public interface IPipelineExecutionService { - Task ExecutePipelineAsync( + Task ExecutePipelineAsync( IEnumerable nodes, BitmapSource source, IProgress progress = null, diff --git a/XplorePlane/Services/Pipeline/PipelineExecutionService.cs b/XplorePlane/Services/Pipeline/PipelineExecutionService.cs index 648c42a..b28c2c8 100644 --- a/XplorePlane/Services/Pipeline/PipelineExecutionService.cs +++ b/XplorePlane/Services/Pipeline/PipelineExecutionService.cs @@ -21,7 +21,7 @@ namespace XplorePlane.Services _imageProcessingService = imageProcessingService ?? throw new ArgumentNullException(nameof(imageProcessingService)); } - public async Task ExecutePipelineAsync( + public async Task ExecutePipelineAsync( IEnumerable nodes, BitmapSource source, IProgress progress = null, @@ -35,11 +35,13 @@ namespace XplorePlane.Services .ToList(); if (enabledNodes.Count == 0) - return source; + return new PipelineExecutionResult(source, null); var current = ScaleForPreview(source); var total = enabledNodes.Count; + IReadOnlyDictionary? templateOverlayData = null; + for (var step = 0; step < total; step++) { cancellationToken.ThrowIfCancellationRequested(); @@ -63,9 +65,11 @@ namespace XplorePlane.Services try { - current = await _imageProcessingService.ProcessImageAsync( + var (img, output) = await _imageProcessingService.ProcessImageWithOutputAsync( current, node.OperatorKey, parameters, null, cancellationToken); + current = img; + if (current == null) { throw new PipelineExecutionException( @@ -73,6 +77,12 @@ namespace XplorePlane.Services node.Order, node.OperatorKey); } + + if (step == total - 1) + { + templateOverlayData = TemplateMatchOverlayRenderer.TrySnapshotOutputForOverlay( + node.OperatorKey, parameters, output); + } } catch (OperationCanceledException) { @@ -97,7 +107,7 @@ namespace XplorePlane.Services if (!current.IsFrozen) current.Freeze(); - return current; + return new PipelineExecutionResult(current, templateOverlayData); } private static BitmapSource ScaleForPreview(BitmapSource source) diff --git a/XplorePlane/Themes/Generic.xaml b/XplorePlane/Themes/Generic.xaml index 90b8434..675a516 100644 --- a/XplorePlane/Themes/Generic.xaml +++ b/XplorePlane/Themes/Generic.xaml @@ -33,7 +33,7 @@ x:Name="Thumb" Width="18" Height="18" - Margin="3" + Margin="3,3,3,3" HorizontalAlignment="Left" Background="{TemplateBinding ThumbBrush}" CornerRadius="9"> @@ -44,13 +44,12 @@ Opacity="0.2" ShadowDepth="1" /> - - - + + @@ -61,8 +60,8 @@ Duration="0:0:0.2"> - - + + - - + + + @@ -167,4 +167,4 @@ - + \ No newline at end of file diff --git a/XplorePlane/ViewModels/Cnc/CncInspectionModulePipelineViewModel.cs b/XplorePlane/ViewModels/Cnc/CncInspectionModulePipelineViewModel.cs index bf7c2d7..426744d 100644 --- a/XplorePlane/ViewModels/Cnc/CncInspectionModulePipelineViewModel.cs +++ b/XplorePlane/ViewModels/Cnc/CncInspectionModulePipelineViewModel.cs @@ -87,7 +87,11 @@ namespace XplorePlane.ViewModels.Cnc public PipelineNodeViewModel SelectedNode { get => _selectedNode; - set => SetProperty(ref _selectedNode, value); + set + { + if (!SetProperty(ref _selectedNode, value)) + return; + } } public string StatusMessage @@ -476,11 +480,11 @@ namespace XplorePlane.ViewModels.Cnc try { _logger.Info("[图像链路][CNC] ExecutePreviewAsync:开始执行,节点数={Count}", PipelineNodes.Count); - var result = await _executionService.ExecutePipelineAsync(GetNodesInExecutionScope(), sourceImage, null, token); + var execResult = await _executionService.ExecutePipelineAsync(GetNodesInExecutionScope(), sourceImage, null, token); _logger.Info("[图像链路][CNC] ExecutePreviewAsync:执行完成,推送结果图像"); - _mainViewportService.SetManualImage(result, string.Empty); + _mainViewportService.SetManualImage(execResult.Image, string.Empty); _eventAggregator?.GetEvent() - .Publish(new PipelinePreviewUpdatedPayload(result, StatusMessage)); + .Publish(new PipelinePreviewUpdatedPayload(execResult.Image, StatusMessage)); } catch (OperationCanceledException) { diff --git a/XplorePlane/ViewModels/ImageProcessing/OperatorToolboxViewModel.cs b/XplorePlane/ViewModels/ImageProcessing/OperatorToolboxViewModel.cs index 027f803..a6d46d1 100644 --- a/XplorePlane/ViewModels/ImageProcessing/OperatorToolboxViewModel.cs +++ b/XplorePlane/ViewModels/ImageProcessing/OperatorToolboxViewModel.cs @@ -129,7 +129,8 @@ namespace XplorePlane.ViewModels "数学运算" => 3, "形态学处理" => 4, "边缘检测" => 5, - "检测分析" => 6, + "定位识别" => 6, + "检测分析" => 7, _ => 99 }; diff --git a/XplorePlane/ViewModels/ImageProcessing/PipelineEditorViewModel.cs b/XplorePlane/ViewModels/ImageProcessing/PipelineEditorViewModel.cs index e21d72f..0bbb6d7 100644 --- a/XplorePlane/ViewModels/ImageProcessing/PipelineEditorViewModel.cs +++ b/XplorePlane/ViewModels/ImageProcessing/PipelineEditorViewModel.cs @@ -9,11 +9,16 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Input; +using System.Windows.Media; using System.Windows.Media.Imaging; +using System.Windows; +using System.Windows.Controls; +using XplorePlane.Services; +using XplorePlane.ViewModels; +using XP.ImageProcessing.RoiControl.Controls; using XP.Common.Logging.Interfaces; using XplorePlane.Events; using XplorePlane.Models; -using XplorePlane.Services; using XplorePlane.Services.Storage; namespace XplorePlane.ViewModels @@ -47,6 +52,9 @@ namespace XplorePlane.ViewModels private CancellationTokenSource _executionCts; private CancellationTokenSource _debounceCts; + private PolygonRoiCanvas _pipelinePreviewCanvas; + private Image _templateMatchOverlayImage; + public PipelineEditorViewModel( IImageProcessingService imageProcessingService, IPipelineExecutionService executionService, @@ -99,8 +107,11 @@ namespace XplorePlane.ViewModels get => _selectedNode; set { - if (SetProperty(ref _selectedNode, value) && value != null) - LoadNodeParameters(value); + if (SetProperty(ref _selectedNode, value)) + { + if (value != null) + LoadNodeParameters(value); + } } } @@ -111,6 +122,7 @@ namespace XplorePlane.ViewModels { if (SetProperty(ref _sourceImage, value)) { + RemoveTemplateMatchOverlay(); ExecutePipelineCommand.RaiseCanExecuteChanged(); RaisePropertyChanged(nameof(DisplayImage)); TriggerDebouncedExecution(); @@ -124,7 +136,11 @@ namespace XplorePlane.ViewModels set { if (SetProperty(ref _previewImage, value)) + { + if (value == null) + RemoveTemplateMatchOverlay(); RaisePropertyChanged(nameof(DisplayImage)); + } } } @@ -461,13 +477,17 @@ namespace XplorePlane.ViewModels var progress = new Progress(p => SetInfoStatus($"执行中:{p.CurrentOperator} ({p.CurrentStep}/{p.TotalSteps})")); - var result = await _executionService.ExecutePipelineAsync( + RemoveTemplateMatchOverlay(); + + var execResult = await _executionService.ExecutePipelineAsync( executionNodes, SourceImage, progress, token); - PreviewImage = result; + PreviewImage = execResult.Image; + ApplyTemplateMatchOverlay(execResult); + SetInfoStatus(BuildExecutionCompletedMessage(executionNodes.Count)); _logger.Info("[图像链路] ExecutePipelineAsync:执行完成,准备发布 PipelinePreviewUpdatedEvent"); - PublishPipelinePreviewUpdated(result, StatusMessage); + PublishPipelinePreviewUpdated(execResult.Image, StatusMessage); } catch (OperationCanceledException) { @@ -517,6 +537,7 @@ namespace XplorePlane.ViewModels { IsStatusError = true; StatusMessage = message; + RemoveTemplateMatchOverlay(); PublishPipelinePreviewUpdated(PreviewImage ?? SourceImage, message); } @@ -593,6 +614,61 @@ namespace XplorePlane.ViewModels .Publish(new PipelinePreviewUpdatedPayload(bitmap, statusMessage)); } + /// 由流水线编辑器窗口在 Loaded 时挂上,用于在底图上叠加模板匹配线框(与 BGA 工具分层一致)。 + public void AttachPreviewCanvas(PolygonRoiCanvas canvas) + { + _pipelinePreviewCanvas = canvas; + } + + private void ApplyTemplateMatchOverlay(PipelineExecutionResult execResult) + { + RemoveTemplateMatchOverlay(); + if (_pipelinePreviewCanvas == null || execResult.TemplateMatchOverlayData == null) + return; + + var overlay = TemplateMatchOverlayRenderer.CreateTransparentOverlay( + execResult.Image.PixelWidth, + execResult.Image.PixelHeight, + execResult.TemplateMatchOverlayData); + if (overlay == null) + return; + + ShowTemplateMatchOverlay(overlay); + } + + private void ShowTemplateMatchOverlay(BitmapSource overlayBmp) + { + if (_pipelinePreviewCanvas == null) + return; + + RemoveTemplateMatchOverlay(); + + _templateMatchOverlayImage = new Image + { + Source = overlayBmp, + IsHitTestVisible = false, + Stretch = Stretch.Fill + }; + _templateMatchOverlayImage.SetBinding(FrameworkElement.WidthProperty, + new System.Windows.Data.Binding("CanvasWidth") { Source = _pipelinePreviewCanvas }); + _templateMatchOverlayImage.SetBinding(FrameworkElement.HeightProperty, + new System.Windows.Data.Binding("CanvasHeight") { Source = _pipelinePreviewCanvas }); + + if (_pipelinePreviewCanvas.FindName("mainCanvas") is Canvas mainCanvas) + { + int insertIndex = Math.Min(1, mainCanvas.Children.Count); + mainCanvas.Children.Insert(insertIndex, _templateMatchOverlayImage); + } + } + + private void RemoveTemplateMatchOverlay() + { + if (_templateMatchOverlayImage == null || _pipelinePreviewCanvas == null) + return; + _pipelinePreviewCanvas.RemoveFromCanvas(_templateMatchOverlayImage); + _templateMatchOverlayImage = null; + } + private void OnManualImageLoaded(ManualImageLoadedPayload payload) { if (payload?.Image == null) return; @@ -635,6 +711,7 @@ namespace XplorePlane.ViewModels SelectedNode = null; ExecutionEndNode = null; PipelineName = "新建流水线"; + RemoveTemplateMatchOverlay(); PreviewImage = null; _currentFilePath = null; PipelineFileDisplayName = DefaultPipelineFileDisplayName; diff --git a/XplorePlane/ViewModels/Main/MainViewModel.cs b/XplorePlane/ViewModels/Main/MainViewModel.cs index 25d7817..854e197 100644 --- a/XplorePlane/ViewModels/Main/MainViewModel.cs +++ b/XplorePlane/ViewModels/Main/MainViewModel.cs @@ -1,5 +1,8 @@ +using Emgu.CV; +using Emgu.CV.Structure; using Microsoft.Win32; using Prism.Commands; +using Prism.Dialogs; using Prism.Events; using Prism.Ioc; using Prism.Mvvm; @@ -10,8 +13,14 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows; +using System.Windows.Media; using System.Windows.Media.Imaging; -using System.Windows.Threading; +using XP.Camera.Calibration; +using XP.Common.GeneralForm.Views; +using XP.Common.Logging.Interfaces; +using XP.Common.PdfViewer.Interfaces; +using XP.Hardware.MotionControl.Abstractions; +using XP.Hardware.MotionControl.Services; using XplorePlane.Events; using XplorePlane.Services.MainViewport; using XplorePlane.Services.Recording; @@ -32,7 +41,6 @@ namespace XplorePlane.ViewModels public class MainViewModel : BindableBase { private const double CncEditorHostWidth = 452d; - private readonly ILoggerService _logger; private readonly IContainerProvider _containerProvider; private readonly IEventAggregator _eventAggregator; @@ -53,6 +61,7 @@ namespace XplorePlane.ViewModels } private string _statusMessage = "就绪"; + public string StatusMessage { get => _statusMessage; @@ -88,6 +97,7 @@ namespace XplorePlane.ViewModels // 导航命令 public DelegateCommand NavigateHomeCommand { get; set; } + public DelegateCommand NavigateInspectCommand { get; set; } public DelegateCommand OpenFileCommand { get; set; } public DelegateCommand ExportCommand { get; set; } @@ -96,6 +106,7 @@ namespace XplorePlane.ViewModels // 窗口打开命令 public DelegateCommand OpenImageProcessingCommand { get; } + public DelegateCommand LoadImageCommand { get; } public DelegateCommand OpenPipelineEditorCommand { get; } public DelegateCommand OpenCncEditorCommand { get; } @@ -104,7 +115,6 @@ namespace XplorePlane.ViewModels public DelegateCommand OpenToolboxCommand { get; } public DelegateCommand OpenLibraryVersionsCommand { get; } public DelegateCommand OpenUserManualCommand { get; } - public DelegateCommand OpenCameraSettingsCommand { get; } public DelegateCommand OpenSettingsCommand { get; } public DelegateCommand OpenDebugPanelCommand { get; } public DelegateCommand BrowseDataRootPathCommand { get; } @@ -125,34 +135,55 @@ namespace XplorePlane.ViewModels public DelegateCommand RunCncCommand { get; } public DelegateCommand StopCncCommand { get; } + //导航相机 + + public DelegateCommand OpenCameraSettingsCommand { get; } + public DelegateCommand OpenCameraChessboardCalibrationCommand { get; } + public DelegateCommand OpenCameraCalibrationCommand { get; } + // 硬件命令 public DelegateCommand AxisResetCommand { get; } + public DelegateCommand OpenDoorCommand { get; } public DelegateCommand CloseDoorCommand { get; } public DelegateCommand OpenDetectorConfigCommand { get; } public DelegateCommand OpenMotionDebugCommand { get; } public DelegateCommand OpenPlcAddrConfigCommand { get; } public DelegateCommand OpenRaySourceConfigCommand { get; } + public DelegateCommand OpenReportConfigCommand { get; } public DelegateCommand WarmUpCommand { get; } // 测量命令 public DelegateCommand PointDistanceMeasureCommand { get; } + public DelegateCommand PointLineDistanceMeasureCommand { get; } public DelegateCommand AngleMeasureCommand { get; } public DelegateCommand ThroughHoleFillRateMeasureCommand { get; } - public DelegateCommand BgaVoidMeasureCommand { get; } public DelegateCommand BgaDetectionCommand { get; } public DelegateCommand VoidDetectionCommand { get; } public DelegateCommand BubbleMeasureCommand { get; } + private bool _isScaleBarVisible; + public bool IsScaleBarVisible + { + get => _isScaleBarVisible; + set => SetProperty(ref _isScaleBarVisible, value); + } + // 辅助线命令 public DelegateCommand ToggleCrosshairCommand { get; } - // 录屏命令 - public DelegateCommand ToggleRecordingCommand { get; } + // 图像处理命令 + public DelegateCommand WhiteBackgroundDetectionCommand { get; } + + public DelegateCommand BlackBackgroundDetectionCommand { get; } + public DelegateCommand GrayscaleCommand { get; } + public DelegateCommand SharpenCommand { get; } + public DelegateCommand EnhanceCommand { get; } // 设置命令 public DelegateCommand OpenLanguageSwitcherCommand { get; } + public DelegateCommand OpenRealTimeLogViewerCommand { get; } public DelegateCommand UseLiveDetectorSourceCommand { get; } @@ -166,6 +197,7 @@ namespace XplorePlane.ViewModels _mainViewportService.SetRealtimeDisplayEnabled(value); RaisePropertyChanged(); + RaisePropertyChanged(nameof(IsMeasurementToolsEnabled)); } } @@ -230,6 +262,7 @@ namespace XplorePlane.ViewModels // 窗口引用(单例窗口防止重复打开) private Window _motionDebugWindow; + private Window _detectorConfigWindow; private Window _plcAddrConfigWindow; private Window _realTimeLogViewerWindow; @@ -302,9 +335,8 @@ namespace XplorePlane.ViewModels ClearCommand = new DelegateCommand(OnClear); EditPropertiesCommand = new DelegateCommand(OnEditProperties); - LoadImageCommand = new DelegateCommand(ExecuteLoadImage); - + OpenCncEditorCommand = new DelegateCommand(ExecuteOpenCncEditor); OpenMatrixEditorCommand = new DelegateCommand(() => ShowWindow(new Views.Cnc.MatrixEditorWindow(), "矩阵编辑")); OpenInspectionReportViewerCommand = new DelegateCommand(ExecuteOpenInspectionReportViewer); @@ -312,6 +344,9 @@ namespace XplorePlane.ViewModels OpenLibraryVersionsCommand = new DelegateCommand(() => ShowWindow(new Views.LibraryVersionsWindow(), "关于")); OpenUserManualCommand = new DelegateCommand(ExecuteOpenUserManual); OpenCameraSettingsCommand = new DelegateCommand(ExecuteOpenCameraSettings); + OpenCameraChessboardCalibrationCommand = new DelegateCommand(ExecuteOpenCameraChessboardCalibration); + OpenCameraCalibrationCommand = new DelegateCommand(ExecuteOpenCameraCalibration); + OpenSettingsCommand = new DelegateCommand(ExecuteOpenSettings); OpenDebugPanelCommand = new DelegateCommand(ExecuteOpenDebugPanel); BrowseDataRootPathCommand = new DelegateCommand(ExecuteBrowseDataRootPath); @@ -342,7 +377,6 @@ namespace XplorePlane.ViewModels PointLineDistanceMeasureCommand = new DelegateCommand(ExecutePointLineDistanceMeasure); AngleMeasureCommand = new DelegateCommand(ExecuteAngleMeasure); ThroughHoleFillRateMeasureCommand = new DelegateCommand(ExecuteThroughHoleFillRateMeasure); - BgaVoidMeasureCommand = new DelegateCommand(ExecuteBgaVoidMeasure); BgaDetectionCommand = new DelegateCommand(ExecuteBgaDetection); VoidDetectionCommand = new DelegateCommand(ExecuteVoidDetection); BubbleMeasureCommand = new DelegateCommand(ExecuteBubbleMeasure); @@ -351,6 +385,13 @@ namespace XplorePlane.ViewModels ToggleCrosshairCommand = new DelegateCommand(() => _eventAggregator.GetEvent().Publish()); + // 图像处理命令 + WhiteBackgroundDetectionCommand = new DelegateCommand(ExecuteWhiteBackgroundDetection); + BlackBackgroundDetectionCommand = new DelegateCommand(ExecuteBlackBackgroundDetection); + GrayscaleCommand = new DelegateCommand(ExecuteGrayscale); + SharpenCommand = new DelegateCommand(ExecuteSharpen); + EnhanceCommand = new DelegateCommand(ExecuteEnhance); + AxisResetCommand = new DelegateCommand(ExecuteAxisReset); OpenDoorCommand = new DelegateCommand(ExecuteOpenDoor); CloseDoorCommand = new DelegateCommand(ExecuteCloseDoor); @@ -358,6 +399,7 @@ namespace XplorePlane.ViewModels OpenMotionDebugCommand = new DelegateCommand(ExecuteOpenMotionDebug); OpenPlcAddrConfigCommand = new DelegateCommand(ExecuteOpenPlcAddrConfig); OpenRaySourceConfigCommand = new DelegateCommand(ExecuteOpenRaySourceConfig); + OpenReportConfigCommand = new DelegateCommand(ExecuteOpenReportConfig); WarmUpCommand = new DelegateCommand(ExecuteWarmUp); OpenLanguageSwitcherCommand = new DelegateCommand(ExecuteOpenLanguageSwitcher); @@ -383,6 +425,14 @@ namespace XplorePlane.ViewModels public string CncStatusMessage => _cncEditorViewModel.StatusMessage; public bool CncHasExecutionError => _cncEditorViewModel.HasExecutionError; + private string _cursorInfoText = "X: -- Y: -- Gray: --"; + + public string CursorInfoText + { + get => _cursorInfoText; + set => SetProperty(ref _cursorInfoText, value); + } + private void ShowWindow(Window window, string name) { window.Owner = Application.Current.MainWindow; @@ -512,6 +562,9 @@ namespace XplorePlane.ViewModels try { var manualPath = ConfigurationManager.AppSettings["UserManual"]; + manualPath = Path.IsPathRooted(manualPath) + ? manualPath + : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, manualPath); if (string.IsNullOrEmpty(manualPath)) { _logger.Warn("User manual path is not configured."); @@ -561,6 +614,50 @@ namespace XplorePlane.ViewModels } } + private void ExecuteOpenCameraChessboardCalibration() + { + var chessboardWindow = new System.Windows.Window + { + Title = XP.Common.Resources.Resources.ChessboardToolTitle, + Width = 1600, + Height = 900, + WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen, + Icon = System.Windows.Application.Current.MainWindow?.Icon + }; + + var calibrationDialogService = new XP.Camera.Calibration.DefaultCalibrationDialogService(); + var chessboardViewModel = new XP.Camera.Calibration.ViewModels.ChessboardCalibrationViewModel(calibrationDialogService); + var chessboardControl = new XP.Camera.Calibration.Controls.ChessboardCalibrationControl + { + DataContext = chessboardViewModel + }; + + chessboardWindow.Content = chessboardControl; + chessboardWindow.ShowDialog(); + } + + private void ExecuteOpenCameraCalibration() + { + var calibrationWindow = new System.Windows.Window + { + Title = XP.Common.Resources.Resources.CalibrationToolTitle, + Width = 1400, + Height = 850, + WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen, + Icon = System.Windows.Application.Current.MainWindow?.Icon + }; + + var calibrationDialogService = new XP.Camera.Calibration.DefaultCalibrationDialogService(); + var calibrationViewModel = new XP.Camera.Calibration.ViewModels.CalibrationViewModel(calibrationDialogService); + var calibrationControl = new XP.Camera.Calibration.Controls.CalibrationControl + { + DataContext = calibrationViewModel + }; + + calibrationWindow.Content = calibrationControl; + calibrationWindow.ShowDialog(); + } + private void ExecuteOpenSettings() { try @@ -817,6 +914,16 @@ namespace XplorePlane.ViewModels () => new XP.Hardware.RaySource.Views.RaySourceConfigWindow(), "Ray Source Config"); } + private void ExecuteOpenReportConfig() + { + ShowOrActivate(_reportConfigWindow, w => _reportConfigWindow = w, + () => + { + var viewModel = _containerProvider.Resolve(); + return new XP.ReportEngine.Views.ReportDemoWindow(viewModel); + }, "报告配置"); + } + private void ExecuteLoadImage() { var dialog = new OpenFileDialog @@ -899,11 +1006,10 @@ namespace XplorePlane.ViewModels if (viewportVm?.ImageSource != null) return true; } catch { } - HexMessageBox.Show("Please load an image first", MessageBoxButton.OK, MessageBoxImage.Information); + HexMessageBox.Show("Please load an image first!", MessageBoxButton.OK, MessageBoxImage.Information); return false; } - private void ExecutePointDistanceMeasure() { if (!CheckImageLoaded()) return; @@ -932,31 +1038,6 @@ namespace XplorePlane.ViewModels _eventAggregator.GetEvent().Publish(MeasurementToolMode.ThroughHoleFillRate); } - private Window _bgaMeasurePanel; - - private void ExecuteBgaVoidMeasure() - { - if (!CheckImageLoaded()) return; - _logger.Info("BGA void measurement triggered."); - _eventAggregator.GetEvent().Publish(MeasurementToolMode.BgaVoid); - - if (_bgaMeasurePanel != null && _bgaMeasurePanel.IsVisible) - { - _bgaMeasurePanel.Activate(); - return; - } - - _bgaMeasurePanel = new Views.ImageProcessing.BgaMeasurePanel - { - Owner = System.Windows.Application.Current.MainWindow - }; - _bgaMeasurePanel.Closed += (s, e) => - { - _eventAggregator.GetEvent().Publish(MeasurementToolMode.None); - }; - _bgaMeasurePanel.Show(); - } - private Window _bgaDetectionPanel; private void ExecuteBgaDetection() @@ -1024,7 +1105,150 @@ namespace XplorePlane.ViewModels _eventAggregator.GetEvent().Publish(MeasurementToolMode.None); }; _bubbleMeasurePanel.Show(); + } + private void ExecuteWhiteBackgroundDetection() + { + if (!CheckImageLoaded()) return; + _logger.Info("White background detection triggered."); + // TODO: 实现白底检测逻辑 + } + + private void ExecuteBlackBackgroundDetection() + { + if (!CheckImageLoaded()) return; + _logger.Info("Black background detection triggered."); + // TODO: 实现黑底检测逻辑 + } + + private void ExecuteGrayscale() + { + if (!CheckImageLoaded()) return; + _logger.Info("Grayscale conversion triggered."); + // TODO: 实现灰度转换逻辑 + } + + private void ExecuteSharpen() + { + if (!CheckImageLoaded()) return; + _logger.Info("Sharpen triggered."); + + try + { + var viewportVm = _containerProvider.Resolve(); + var imageSource = viewportVm?.ImageSource as BitmapSource; + if (imageSource == null) return; + + var inputImage = BitmapSourceToImage(imageSource); + if (inputImage == null) return; + + var processor = new XP.ImageProcessing.Processors.SharpenProcessor(); + processor.SetParameter("Method", "UnsharpMask"); + processor.SetParameter("Strength", 0.2); + processor.SetParameter("KernelSize", 3); + + var result = processor.Process(inputImage); + var resultBitmap = ImageToBitmapSource(result); + + _mainViewportService.SetManualImage(resultBitmap, "Sharpen"); + + inputImage.Dispose(); + result.Dispose(); + + _logger.Info("Sharpen completed."); + } + catch (Exception ex) + { + _logger.Error(ex, "Sharpen failed."); + HexMessageBox.Show($"Sharpen failed: {ex.Message}", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + private void ExecuteEnhance() + { + if (!CheckImageLoaded()) return; + _logger.Info("Enhance triggered."); + + try + { + var viewportVm = _containerProvider.Resolve(); + var imageSource = viewportVm?.ImageSource as BitmapSource; + if (imageSource == null) return; + + var inputImage = BitmapSourceToImage(imageSource); + if (inputImage == null) return; + + var processor = new XP.ImageProcessing.Processors.HistogramEqualizationProcessor(); + + var result = processor.Process(inputImage); + var resultBitmap = ImageToBitmapSource(result); + + _mainViewportService.SetManualImage(resultBitmap, "Enhance"); + + inputImage.Dispose(); + result.Dispose(); + + _logger.Info("Enhance completed."); + } + catch (Exception ex) + { + _logger.Error(ex, "Enhance failed."); + HexMessageBox.Show($"Enhance failed: {ex.Message}", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + private Image? BitmapSourceToImage(BitmapSource bitmapSource) + { + // 转换为可用的图像格式 + BitmapSource source = bitmapSource; + + // 如果不是 Gray8 格式,转换为 Gray8 + if (bitmapSource.Format != PixelFormats.Gray8) + { + source = new FormatConvertedBitmap(bitmapSource, PixelFormats.Gray8, null, 0); + } + + // 获取原始像素数据 + int width = source.PixelWidth; + int height = source.PixelHeight; + int stride = width; // Gray8 每个像素 1 字节 + byte[] pixels = new byte[width * height]; + source.CopyPixels(pixels, stride, 0); + + // 创建 Emgu CV Image + var image = new Image(width, height); + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + image.Data[y, x, 0] = pixels[y * stride + x]; + } + } + + return image; + } + + private BitmapSource ImageToBitmapSource(Image image) + { + int width = image.Width; + int height = image.Height; + int stride = width; + byte[] pixels = new byte[width * height]; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + pixels[y * stride + x] = image.Data[y, x, 0]; + } + } + + var bitmapSource = BitmapSource.Create( + width, height, 96, 96, + PixelFormats.Gray8, null, pixels, stride); + + bitmapSource.Freeze(); + return bitmapSource; } private void ExecuteOpenLanguageSwitcher() @@ -1106,6 +1330,7 @@ namespace XplorePlane.ViewModels _logger.Info("[Image] OnPipelinePreviewUpdated received a pipeline preview image and pushed it to MainViewportService."); _mainViewportService.SetManualImage(payload.Image, string.Empty); } + public sealed record BuiltInInspectionModuleItem(string DisplayName, string FilePath); #endregion @@ -1214,6 +1439,6 @@ namespace XplorePlane.ViewModels _statusMessageTimer.Start(); } - #endregion + #endregion 测量命令实现 } -} +} \ No newline at end of file diff --git a/XplorePlane/ViewModels/Main/NavigationPropertyPanelViewModel.cs b/XplorePlane/ViewModels/Main/NavigationPropertyPanelViewModel.cs index 8785474..586e99f 100644 --- a/XplorePlane/ViewModels/Main/NavigationPropertyPanelViewModel.cs +++ b/XplorePlane/ViewModels/Main/NavigationPropertyPanelViewModel.cs @@ -24,11 +24,19 @@ namespace XplorePlane.ViewModels #region Properties + private BitmapSource _defaultImageSource; + + public BitmapSource DefaultImageSource + { + get => _defaultImageSource; + set => SetProperty(ref _defaultImageSource, value); + } + private BitmapSource? _cameraImageSource; public BitmapSource? CameraImageSource { - get => _cameraImageSource; + get => _cameraImageSource ?? _defaultImageSource; set => SetProperty(ref _cameraImageSource, value); } @@ -181,6 +189,10 @@ namespace XplorePlane.ViewModels RefreshCameraParamsCommand = new DelegateCommand(RefreshCameraParams, () => IsCameraConnected); OpenCameraSettingsCommand = new DelegateCommand(OpenCameraSettings, () => IsCameraConnected); + // 加载默认图片 + _defaultImageSource = new BitmapImage(new Uri("pack://application:,,,/Assets/Icons/NoCamera.png")); + _cameraImageSource = _defaultImageSource; + CameraStatusText = "正在检索相机..."; } diff --git a/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml b/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml deleted file mode 100644 index 87aad82..0000000 --- a/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml.cs b/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml.cs deleted file mode 100644 index ee34e2f..0000000 --- a/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Windows; -using XP.ImageProcessing.RoiControl.Controls; - -namespace XplorePlane.Views.ImageProcessing -{ - public partial class BgaMeasurePanel : Window - { - private PolygonRoiCanvas _canvas; - - public BgaMeasurePanel() - { - InitializeComponent(); - Loaded += OnLoaded; - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - try - { - var mainWin = Owner as MainWindow; - if (mainWin != null) - _canvas = FindChild(mainWin); - } - catch { } - - // 模式切换:通知 canvas 切换气泡/焊球 - RbVoid.Checked += (s, ev) => - { - if (_canvas != null) _canvas.SetBgaDrawBall(false); - }; - RbBall.Checked += (s, ev) => - { - if (_canvas != null) _canvas.SetBgaDrawBall(true); - }; - - // VoidLimit 同步 - SliderVoidLimit.ValueChanged += (s, ev) => - { - TbVoidLimit.Text = SliderVoidLimit.Value.ToString("F1"); - _canvas?.SetBgaVoidLimit(SliderVoidLimit.Value); - }; - - // 监听测量完成事件更新结果 - if (_canvas != null) - { - _canvas.MeasureCompleted += (s, ev) => - { - if (ev is MeasureCompletedEventArgs args && args.MeasureType == "BgaVoid") - { - TbResult.Text = $"空隙率: {args.Distance:F1}%"; - } - }; - } - } - - private void Finish_Click(object sender, RoutedEventArgs e) - { - Close(); - } - - private static T FindChild(DependencyObject parent) where T : DependencyObject - { - int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(parent); - for (int i = 0; i < count; i++) - { - var child = System.Windows.Media.VisualTreeHelper.GetChild(parent, i); - if (child is T t) return t; - var result = FindChild(child); - if (result != null) return result; - } - return null; - } - } -} diff --git a/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml b/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml index e4fc177..8989ad2 100644 --- a/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml +++ b/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml @@ -3,7 +3,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="气泡测量工具" - Width="340" Height="380" + Width="420" Height="380" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" Topmost="True" ShowInTaskbar="False" @@ -60,9 +60,15 @@ - + + + + + + + diff --git a/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml.cs b/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml.cs index 99fa7aa..8a5c022 100644 --- a/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml.cs +++ b/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml.cs @@ -1,6 +1,9 @@ +using System; +using System.Collections.ObjectModel; using System.Windows; using Prism.Ioc; using XP.ImageProcessing.RoiControl.Controls; +using XP.ImageProcessing.RoiControl.Models; using XplorePlane.ViewModels; namespace XplorePlane.Views.ImageProcessing @@ -8,31 +11,33 @@ namespace XplorePlane.Views.ImageProcessing public partial class BubbleMeasurePanel : Window { private PolygonRoiCanvas _canvas; + private PolygonROI _polyRoiShape; + private bool _polyRoiActive; // 标记多边形 ROI 是否激活 public BubbleMeasurePanel() { InitializeComponent(); Loaded += OnLoaded; + Closed += OnClosed; } private void OnLoaded(object sender, RoutedEventArgs e) { - // 获取主界面的 RoiCanvas try { var mainWin = Owner as MainWindow; if (mainWin != null) - { _canvas = FindChild(mainWin); - } } catch { } // 工具切换 - RbRoi.Checked += (s, ev) => _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Roi); - RbWand.Checked += (s, ev) => _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Wand); - RbBrush.Checked += (s, ev) => _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Brush); - RbEraser.Checked += (s, ev) => _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Eraser); + RbRoi.Checked += (s, ev) => { ClearAllBubbleRoi(); _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Roi); }; + RbRoiCircle.Checked += (s, ev) => { ClearAllBubbleRoi(); _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.RoiCircle); }; + RbRoiPolygon.Checked += (s, ev) => { ClearAllBubbleRoi(); _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.RoiPolygon); EnablePolyRoi(); }; + RbWand.Checked += (s, ev) => { _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Wand); FinalizePolyRoi(); }; + RbBrush.Checked += (s, ev) => { _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Brush); FinalizePolyRoi(); }; + RbEraser.Checked += (s, ev) => { _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Eraser); FinalizePolyRoi(); }; // 阈值同步 SliderThreshold.ValueChanged += (s, ev) => @@ -52,36 +57,136 @@ namespace XplorePlane.Views.ImageProcessing TbVoidLimit.TextChanged += (s, ev) => { if (double.TryParse(TbVoidLimit.Text, out double val)) - _canvas?.SetBubbleVoidLimit(System.Math.Clamp(val, 0, 100)); + _canvas?.SetBubbleVoidLimit(Math.Clamp(val, 0, 100)); }; - // 初始同步:确保面板默认值推送到 canvas + // 初始同步 _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Roi); _canvas?.SetBubbleThreshold((int)SliderThreshold.Value); _canvas?.SetBubbleBrushSize((int)SliderBrushSize.Value); if (double.TryParse(TbVoidLimit.Text, out double initLimit)) - _canvas?.SetBubbleVoidLimit(System.Math.Clamp(initLimit, 0, 100)); + _canvas?.SetBubbleVoidLimit(Math.Clamp(initLimit, 0, 100)); - // 监听 canvas 的工具切换事件(ROI 画完后自动切换时同步面板) if (_canvas != null) { - _canvas.BubbleToolChanged += (s, ev) => - { - // 同步面板 radio button - }; - + _canvas.BubbleToolChanged += (s, ev) => { }; _canvas.MeasureCompleted += (s, ev) => { if (ev is MeasureCompletedEventArgs args && args.MeasureType == "BubbleVoid") - { TbResult.Text = $"空隙率: {args.Distance:F1}%"; - } }; } } + // ── 多边形 ROI(复用 ROIItems 方式)── + + /// 清除所有类型的气泡 ROI(矩形/圆形/多边形) + private void ClearAllBubbleRoi() + { + CleanupPolyRoi(); + _canvas?.ClearBubbleMeasure(); + // 确保多边形点也被清空 + _canvas?.SetBubblePolyPoints(new System.Collections.Generic.List()); + TbResult.Text = "空隙率: --"; + } + + private void EnablePolyRoi() + { + if (_canvas == null) return; + if (_polyRoiShape != null) return; // 已有 + + if (_canvas.ROIItems == null) + _canvas.ROIItems = new ObservableCollection(); + + _polyRoiShape = new PolygonROI { Color = "Red", IsSelected = true }; + _polyRoiActive = true; + _canvas.ROIItems.Add(_polyRoiShape); + _canvas.SelectedROI = _polyRoiShape; + + _polyRoiShape.Points.CollectionChanged += (s, ev) => + { + if (!_polyRoiActive) return; // 已失效的 handler 不处理 + if (ev.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + ev.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove) + { + _canvas.SelectedROI = null; + _canvas.SelectedROI = _polyRoiShape; + SyncPolyToCanvas(); + } + }; + + _canvas.SetValue(System.Windows.Controls.ContextMenuService.IsEnabledProperty, false); + _canvas.AddHandler(PolygonRoiCanvas.CanvasClickedEvent, new RoutedEventHandler(OnCanvasClickedForPoly)); + } + + private void OnCanvasClickedForPoly(object sender, RoutedEventArgs e) + { + if (_polyRoiShape == null) return; + if (e is CanvasClickedEventArgs args) + { + InsertPointToPolygon(args.Position, _polyRoiShape.Points); + _polyRoiShape.IsSelected = true; + _canvas.SelectedROI = _polyRoiShape; + } + } + + /// 将 PolygonROI 的点同步到 canvas 内部的 _bubblePolyPoints + private void SyncPolyToCanvas() + { + if (_canvas == null || _polyRoiShape == null) return; + _canvas.SetBubblePolyPoints(_polyRoiShape.Points); + } + + /// 切换到魔棒/画笔时,锁定多边形 ROI 不可编辑 + private void FinalizePolyRoi() + { + if (_polyRoiShape == null) return; + _polyRoiShape.IsSelected = false; + _polyRoiShape.IsEditable = false; + _canvas?.SetValue(System.Windows.Controls.ContextMenuService.IsEnabledProperty, true); + if (_canvas != null) + _canvas.RemoveHandler(PolygonRoiCanvas.CanvasClickedEvent, new RoutedEventHandler(OnCanvasClickedForPoly)); + _canvas.SelectedROI = null; + } + + private void CleanupPolyRoi() + { + _polyRoiActive = false; + if (_canvas != null) + { + _canvas.RemoveHandler(PolygonRoiCanvas.CanvasClickedEvent, new RoutedEventHandler(OnCanvasClickedForPoly)); + _canvas.SetValue(System.Windows.Controls.ContextMenuService.IsEnabledProperty, true); + } + if (_polyRoiShape != null && _canvas?.ROIItems != null) + { + _canvas.ROIItems.Remove(_polyRoiShape); + _canvas.SelectedROI = null; + _polyRoiShape = null; + } + } + + private void OnClosed(object sender, EventArgs e) + { + // 关闭面板时保留 ROI 但设为不可编辑 + _polyRoiActive = false; + if (_canvas != null) + { + _canvas.RemoveHandler(PolygonRoiCanvas.CanvasClickedEvent, new RoutedEventHandler(OnCanvasClickedForPoly)); + _canvas.SetValue(System.Windows.Controls.ContextMenuService.IsEnabledProperty, true); + } + if (_polyRoiShape != null) + { + _polyRoiShape.IsSelected = false; + _polyRoiShape.IsEditable = false; + _canvas.SelectedROI = null; + } + } + + // ── 通用操作 ── + private void ClearMask_Click(object sender, RoutedEventArgs e) { + CleanupPolyRoi(); _canvas?.ClearBubbleMeasure(); TbResult.Text = "空隙率: --"; } @@ -96,6 +201,34 @@ namespace XplorePlane.Views.ImageProcessing Close(); } + // ── 工具方法 ── + + private static void InsertPointToPolygon(Point newPoint, ObservableCollection points) + { + if (points.Count < 2) { points.Add(newPoint); return; } + + int insertIndex = 0; + double minDistance = double.MaxValue; + double d = PointToSegmentDistance(points[points.Count - 1], points[0], newPoint); + if (d < minDistance) { minDistance = d; insertIndex = 0; } + for (int i = 1; i < points.Count; i++) + { + d = PointToSegmentDistance(points[i - 1], points[i], newPoint); + if (d < minDistance) { minDistance = d; insertIndex = i; } + } + points.Insert(insertIndex, newPoint); + } + + private static double PointToSegmentDistance(Point a, Point b, Point p) + { + double dx = b.X - a.X, dy = b.Y - a.Y; + double lenSq = dx * dx + dy * dy; + if (lenSq < 1e-10) return Math.Sqrt((p.X - a.X) * (p.X - a.X) + (p.Y - a.Y) * (p.Y - a.Y)); + double t = Math.Clamp(((p.X - a.X) * dx + (p.Y - a.Y) * dy) / lenSq, 0, 1); + double projX = a.X + t * dx, projY = a.Y + t * dy; + return Math.Sqrt((p.X - projX) * (p.X - projX) + (p.Y - projY) * (p.Y - projY)); + } + private static T FindChild(DependencyObject parent) where T : DependencyObject { int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(parent); diff --git a/XplorePlane/Views/ImageProcessing/PipelineEditorView.xaml b/XplorePlane/Views/ImageProcessing/PipelineEditorView.xaml index 70fc68e..270f3a3 100644 --- a/XplorePlane/Views/ImageProcessing/PipelineEditorView.xaml +++ b/XplorePlane/Views/ImageProcessing/PipelineEditorView.xaml @@ -292,6 +292,7 @@ - diff --git a/XplorePlane/Views/ImageProcessing/PipelineEditorWindow.xaml.cs b/XplorePlane/Views/ImageProcessing/PipelineEditorWindow.xaml.cs index 0e03fa0..ca1f8b0 100644 --- a/XplorePlane/Views/ImageProcessing/PipelineEditorWindow.xaml.cs +++ b/XplorePlane/Views/ImageProcessing/PipelineEditorWindow.xaml.cs @@ -2,6 +2,7 @@ using Prism.Ioc; using System; using System.Windows; using XplorePlane.ViewModels; +using XP.ImageProcessing.RoiControl.Controls; namespace XplorePlane.Views { @@ -19,6 +20,15 @@ namespace XplorePlane.Views { System.Diagnostics.Debug.WriteLine(ex); } + + Loaded += OnLoaded; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + Loaded -= OnLoaded; + if (DataContext is PipelineEditorViewModel vm) + vm.AttachPreviewCanvas(PipelinePreviewRoiCanvas); } } } diff --git a/XplorePlane/Views/Main/ImagePanelView.xaml b/XplorePlane/Views/Main/ImagePanelView.xaml index 1b49bcf..84f601c 100644 --- a/XplorePlane/Views/Main/ImagePanelView.xaml +++ b/XplorePlane/Views/Main/ImagePanelView.xaml @@ -1,5 +1,6 @@ - + + + diff --git a/XplorePlane/Views/Main/MainWindow.xaml b/XplorePlane/Views/Main/MainWindow.xaml index d4eee20..b372a76 100644 --- a/XplorePlane/Views/Main/MainWindow.xaml +++ b/XplorePlane/Views/Main/MainWindow.xaml @@ -166,8 +166,16 @@ Size="Medium" SmallImage="/Assets/Icons/crosshair.png" Text="辅助线" /> + @@ -175,11 +183,13 @@ @@ -187,11 +197,13 @@ @@ -229,6 +241,7 @@ telerik:ScreenTip.Description="测量两点之间的距离" telerik:ScreenTip.Title="点点距测量" Command="{Binding PointDistanceMeasureCommand}" + IsEnabled="{Binding IsMeasurementToolsEnabled}" Size="Medium" SmallImage="/Assets/Icons/ptop.png" Text="点点距测量" /> @@ -236,6 +249,7 @@ telerik:ScreenTip.Description="测量点到直线的距离" telerik:ScreenTip.Title="点线距测量" Command="{Binding PointLineDistanceMeasureCommand}" + IsEnabled="{Binding IsMeasurementToolsEnabled}" Size="Medium" SmallImage="/Assets/Icons/ptol.png" Text="点线距测量" /> @@ -247,6 +261,7 @@ telerik:ScreenTip.Description="测量两条线之间的角度" telerik:ScreenTip.Title="角度测量" Command="{Binding AngleMeasureCommand}" + IsEnabled="{Binding IsMeasurementToolsEnabled}" Size="Medium" SmallImage="/Assets/Icons/angle.png" Text="角度测量" /> @@ -254,24 +269,19 @@ telerik:ScreenTip.Description="测量通孔填锡率" telerik:ScreenTip.Title="通孔填锡率测量" Command="{Binding ThroughHoleFillRateMeasureCommand}" + IsEnabled="{Binding IsMeasurementToolsEnabled}" Size="Medium" SmallImage="/Assets/Icons/cylinder.png" Text="通孔填锡率" /> - + - @@ -369,7 +379,6 @@ Command="{Binding InsertInspectionModuleCommand}" SmallImage="/Assets/Icons/Module.png" Text="检测模块" /> - --> - - @@ -442,14 +449,13 @@ - - + - + + + + + + + + + + + + + + + + @@ -554,8 +599,6 @@ Command="{Binding OpenLibraryVersionsCommand}" Text="关于" /> - - @@ -566,7 +609,7 @@ - + - + - - - + + + @@ -639,7 +682,7 @@ FontFamily="Consolas" FontSize="11" Foreground="White" - Text="x: 0 y: 0" /> + Text="{Binding CursorInfoText}" /> diff --git a/XplorePlane/Views/Main/NavigationPropertyPanelView.xaml b/XplorePlane/Views/Main/NavigationPropertyPanelView.xaml index a7a1842..6c1916d 100644 --- a/XplorePlane/Views/Main/NavigationPropertyPanelView.xaml +++ b/XplorePlane/Views/Main/NavigationPropertyPanelView.xaml @@ -32,28 +32,30 @@ - + + + - + diff --git a/XplorePlane/Views/Main/ViewportPanelView.xaml b/XplorePlane/Views/Main/ViewportPanelView.xaml index 75f9a38..95ca774 100644 --- a/XplorePlane/Views/Main/ViewportPanelView.xaml +++ b/XplorePlane/Views/Main/ViewportPanelView.xaml @@ -34,25 +34,9 @@ - - - - - - + ImageSource="{Binding ImageSource}" + ScaleBarMmPerPixel="0.139" + ShowScaleBar="{Binding DataContext.IsScaleBarVisible, RelativeSource={RelativeSource AncestorType=Window}}" /> diff --git a/XplorePlane/Views/Main/ViewportPanelView.xaml.cs b/XplorePlane/Views/Main/ViewportPanelView.xaml.cs index 992be28..b2714a1 100644 --- a/XplorePlane/Views/Main/ViewportPanelView.xaml.cs +++ b/XplorePlane/Views/Main/ViewportPanelView.xaml.cs @@ -17,13 +17,19 @@ namespace XplorePlane.Views { private MainViewModel _mainVm; - private void SetStatus(string msg) + private MainViewModel GetMainVm() { if (_mainVm == null) { try { _mainVm = ContainerLocator.Current?.Resolve(); } catch { } } - if (_mainVm != null) _mainVm.StatusMessage = msg; + return _mainVm; + } + + private void SetStatus(string msg) + { + var vm = GetMainVm(); + if (vm != null) vm.StatusMessage = msg; } public ViewportPanelView() @@ -119,6 +125,15 @@ namespace XplorePlane.Views }, Prism.Events.ThreadOption.UIThread); } catch { } + + // 光标信息:从 RoiCanvas.CursorInfo 同步到 MainViewModel + var cursorInfoDesc = System.ComponentModel.DependencyPropertyDescriptor.FromProperty( + PolygonRoiCanvas.CursorInfoProperty, typeof(PolygonRoiCanvas)); + cursorInfoDesc?.AddValueChanged(RoiCanvas, (s, e) => + { + var vm = GetMainVm(); + if (vm != null) vm.CursorInfoText = RoiCanvas.CursorInfo; + }); } private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) diff --git a/XplorePlane/XplorePlane.csproj b/XplorePlane/XplorePlane.csproj index b4960f8..8859b84 100644 --- a/XplorePlane/XplorePlane.csproj +++ b/XplorePlane/XplorePlane.csproj @@ -62,6 +62,7 @@ ..\ExternalLibraries\Telerik ..\bin\ + x64 @@ -186,6 +187,7 @@ +