Option Strict Off
Option Explicit On
Imports System.Runtime.InteropServices
Imports System.Reflection
Imports Microsoft.Win32

Namespace UserSensor
    ' solidifying the interface guid
    <Guid("B21E0E01-C82A-45ac-9F16-9A55683460D1"), _
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
       Public Interface _UserSensor
        <DispId(1)> Function CostSensorFunctionArgs() As Integer
        <DispId(2)> Function CostSensor(ByRef CostValue As Double) As Integer
        <DispId(3)> Function MeasureDistFunctionArgs(ByRef aTypes() As Integer, ByRef aPrompts() As String) As Integer
        <DispId(4)> Function MeasureDist(ByRef objPart1 As Object, ByRef objPart2 As Object, ByRef MinDist As Double) As Integer
        <DispId(5)> Function GetMassFunctionArgs() As Integer
        <DispId(6)> Function GetMass(ByRef MassofPart As Double) As Integer
    End Interface

    ' solidifying the clsID
    <Guid("D8BC1A80-27F0-42ce-A44D-FF7F9406C15B"), ClassInterface(ClassInterfaceType.None), _
    ProgId("clsSensorFunctions_NET,clsSensorFunctions")> Public Class clsSensorFunctions

        Implements _UserSensor

        Public Function CostSensorFunctionArgs() As Integer Implements _UserSensor.CostSensorFunctionArgs
            CostSensorFunctionArgs = 0
        End Function
        Public Function CostSensor(ByRef CostValue As Double) As Integer Implements _UserSensor.CostSensor
            Dim I As Short
            Dim J As Short
            Dim K As Short

            Dim oSEApp As Object
            Dim oSEDoc As Object
            Dim oModelCollection As Object = Nothing
            Dim oFeaturesCollection As Object = Nothing

            Dim oHolesCollection As Object = Nothing
            Dim oUDPsCollection As Object = Nothing
            Dim oPatternsCollection As Object = Nothing
            Dim oLouvers As Object = Nothing
            Dim oBeads As Object = Nothing
            Dim oDimples As Object = Nothing
            Dim oBends As Object = Nothing

            Dim CntHoleFeatures As Short
            Dim CntUDPFeatures As Short
            Dim CntPatternFeatures As Short
            Dim CntMirrorCopyFeatures As Short

            Dim CntTotalHoles As Short
            Dim CntLouvers As Short
            Dim CntBeads As Short
            Dim CntDimples As Short
            Dim CntBends As Short

            Dim TempCnt As Short

            Dim CostPerHole As Double
            Dim CostPerLouver As Double
            Dim CostPerBead As Double
            Dim CostPerDimple As Double
            Dim CostPerBend As Double

            Dim TotalCost As Double
            Dim NumOccur As Integer
            Dim NumFeatPerOccur As Integer
            Dim NumInputFeat As Short

            On Error Resume Next
            oSEApp = GetObject(, "SolidEdge.Application")

            CntTotalHoles = 0
            CntLouvers = 0
            CntBeads = 0
            CntDimples = 0
            CntBends = 0

            CostPerHole = 1.25
            CostPerLouver = 1.15
            CostPerBead = 2.25
            CostPerDimple = 2.05
            CostPerBend = 1.25

            On Error Resume Next
            oSEDoc = oSEApp.ActiveDocument
            If Err.Number Then
                Err.Clear()
                MsgBox("Error getting active document")
            End If

            If oSEDoc.Type = SolidEdgeConstants.DocumentTypeConstants.igSheetMetalDocument Then
                Debug.Print("We have a psm doc")
            Else
                MsgBox("This is not a sheet metal file. Exiting Function.")
                CostSensor = 1
                GoTo P
            End If

            oModelCollection = oSEDoc.Models(1)
            oFeaturesCollection = oModelCollection.Features

            If oFeaturesCollection.Count = 0 Then
                MsgBox("No geometry in the file, exiting function.")
                CostSensor = 1
                GoTo P
            End If

            oHolesCollection = oModelCollection.Holes
            oUDPsCollection = oModelCollection.UserDefinedPatterns
            oPatternsCollection = oModelCollection.Patterns

            oBeads = oModelCollection.Beads
            oBends = oModelCollection.Bends
            oLouvers = oModelCollection.Louvers
            oDimples = oModelCollection.Dimples

            'CntHoleFeatures = HolesCollection.Count
            CntUDPFeatures = oUDPsCollection.Count
            CntPatternFeatures = oPatternsCollection.Count

            'loop thru holes collection to get only those holes whose status is ok or warned
            For J = 1 To oHolesCollection.Count
                If oHolesCollection(J).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureOK Or oHolesCollection(J).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureWarned Then
                    CntHoleFeatures = CntHoleFeatures + 1
                End If
            Next

            CntTotalHoles = CntHoleFeatures

            ' loop thru user defined patterns for number of holes that are ok or warned
            For K = 1 To CntUDPFeatures
                If oUDPsCollection(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureOK Or oUDPsCollection(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureWarned Then
                    TempCnt = oUDPsCollection(K).NumberInputFeatures
                    CntTotalHoles = CntTotalHoles + TempCnt
                    Debug.Print("For " & oUDPsCollection(K).Name & " No holes is " & TempCnt)
                End If
            Next

            TempCnt = 0

            'loop thru pattern features to get holes with ok or warned status
            For K = 1 To CntPatternFeatures
                If oPatternsCollection(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureOK Or oPatternsCollection(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureWarned Then
                    TempCnt = oPatternsCollection(K).NumberOfOccurrences - oPatternsCollection(K).NumberOfInputFeatures
                    CntTotalHoles = CntTotalHoles + TempCnt
                    Debug.Print("For " & oPatternsCollection(K).Name & " No holes is " & TempCnt)
                End If
            Next

            TempCnt = 0

            For K = 1 To oModelCollection.Louvers.Count
                If oLouvers(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureOK Or oLouvers(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureWarned Then
                    CntLouvers = CntLouvers + 1
                End If
            Next

            For K = 1 To oModelCollection.Beads.Count
                If oBeads(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureOK Or oBeads(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureWarned Then
                    CntBeads = CntBeads + 1
                End If
            Next

            For K = 1 To oModelCollection.Bends.Count
                If oBends(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureOK Or oBends(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureWarned Then
                    CntBends = CntBends + 1
                End If
            Next

            For K = 1 To oModelCollection.Dimples.Count
                If oDimples(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureOK Or oDimples(K).Status = SolidEdgeConstants.FeatureStatusConstants.igFeatureWarned Then
                    CntDimples = CntDimples + 1
                End If
            Next

            TotalCost = CostPerHole * CntTotalHoles
            TotalCost = TotalCost + CostPerLouver * CntLouvers
            TotalCost = TotalCost + CostPerBead * CntBeads
            TotalCost = TotalCost + CostPerDimple * CntDimples
            TotalCost = TotalCost + CostPerBend * CntBends

            CostValue = TotalCost

            CostSensor = 0 ' zero returned value indicates success

P:
            If Not oFeaturesCollection Is Nothing Then Marshal.FinalReleaseComObject(oFeaturesCollection)
            If Not oModelCollection Is Nothing Then Marshal.FinalReleaseComObject(oModelCollection)
            If Not oHolesCollection Is Nothing Then Marshal.FinalReleaseComObject(oHolesCollection)
            If Not oUDPsCollection Is Nothing Then Marshal.FinalReleaseComObject(oUDPsCollection)
            If Not oPatternsCollection Is Nothing Then Marshal.FinalReleaseComObject(oPatternsCollection)
            If Not oBeads Is Nothing Then Marshal.FinalReleaseComObject(oBeads)
            If Not oBends Is Nothing Then Marshal.FinalReleaseComObject(oBends)
            If Not oLouvers Is Nothing Then Marshal.FinalReleaseComObject(oLouvers)
            If Not oDimples Is Nothing Then Marshal.FinalReleaseComObject(oDimples)
            oFeaturesCollection = Nothing
            oModelCollection = Nothing
            oHolesCollection = Nothing
            oUDPsCollection = Nothing
            oPatternsCollection = Nothing

            oBeads = Nothing
            oBends = Nothing
            oLouvers = Nothing
            oDimples = Nothing

            Marshal.FinalReleaseComObject(oSEApp)
            Garbage()
            oSEDoc = Nothing
            oSEApp = Nothing

        End Function
        Public Function GetMassFunctionArgs() As Integer Implements _UserSensor.GetMassFunctionArgs
            GetMassFunctionArgs = 0
        End Function
        Public Function GetMass(ByRef MassofPart As Double) As Integer Implements _UserSensor.GetMass
            Dim oSEApp As Object
            Dim oSEDoc As Object

            Dim tmpDensityConst As Integer
            Dim tmpAccuracyConst As Integer

            Dim I As Short
            Dim tmpString As String

            Dim dblDensity As Object
            Dim dblAccuracyIn As Object

            Dim dblAccuracyOut As Double

            Dim dblVolume As Double
            Dim dblArea As Double
            Dim dblMass As Double
            Dim dblCofG(3) As Double
            Dim dblCofV(3) As Double
            Dim dblGlobalMoments(6) As Double
            Dim dblPrincipalMoments(3) As Double
            Dim dblPrincipalAxes(9) As Double
            Dim dblRadiiOfGyration(3) As Double

            Dim MassString As String
            Dim MyMass As Double

            Dim lngStatus As Integer

            oSEApp = GetObject(, "SolidEdge.Application")

            oSEDoc = oSEApp.ActiveDocument
            dblDensity = 0.0#
            dblAccuracyIn = 0.0#

            If oSEDoc.Type = SolidEdgeConstants.DocumentTypeConstants.igSheetMetalDocument Then
                tmpDensityConst = SolidEdgeConstants.SheetMetalGlobalConstants.seSheetMetalGlobalDensity
                tmpAccuracyConst = SolidEdgeConstants.SheetMetalGlobalConstants.seSheetMetalGlobalAccuracyForDensity
            ElseIf oSEDoc.Type = SolidEdgeConstants.DocumentTypeConstants.igPartDocument Then
                tmpDensityConst = SolidEdgeConstants.PartGlobalConstants.sePartGlobalDensity
                tmpAccuracyConst = SolidEdgeConstants.PartGlobalConstants.sePartGlobalAccuracyForDensity
            Else
                MsgBox("This is not a Part or sheet metal file. Exiting Function.")
                GetMass = 1
                GoTo P
            End If

            On Error Resume Next
            Call oSEDoc.GetGlobalParameter(tmpDensityConst, dblDensity)
            If Err.Number <> 0 Then
                Debug.Print(Err.Description)
                Err.Clear()
                MsgBox("error getting density of part")
            End If

            On Error Resume Next
            Call oSEDoc.GetGlobalParameter(tmpAccuracyConst, dblAccuracyIn)
            If Err.Number <> 0 Then
                Debug.Print(Err.Description)
                Err.Clear()
                MsgBox("Error getting accuracy")
            End If

            Debug.Print("Density is: " & dblDensity)
            Debug.Print("Accuracy is: " & dblAccuracyIn)

            If dblDensity = 0.0# Then
                MsgBox("Density cannot be zero. Exiting Function.")
                GetMass = 1
                GoTo P
            End If

            On Error Resume Next

            Call oSEDoc.Models(1).ComputePhysicalProperties(Density:=dblDensity, Accuracy:=dblAccuracyIn, Volume:=dblVolume, Area:=dblArea, Mass:=dblMass, CenterOfGravity:=dblCofG, CenterOfVolume:=dblCofV, GlobalMomentsOfInteria:=dblGlobalMoments, PrincipalMomentsOfInteria:=dblPrincipalMoments, PrincipalAxes:=dblPrincipalAxes, RadiiOfGyration:=dblRadiiOfGyration, RelativeAccuracyAchieved:=dblAccuracyOut, Status:=lngStatus)

            If Err.Number <> 0 Then
                Debug.Print(Err.Description)
                Err.Clear()
                'MsgBox("Error getting mass of part. Exiting Function.")
                'GetMass = 1
                'GoTo P
            End If

            Debug.Print("Density is " & dblDensity & " with accuracy " & dblAccuracyIn)

            'convert mass to units in the File Properties/Advanced Units Tab. This is a string
            MassString = oSEDoc.UnitsOfMeasure.FormatUnit(SolidEdgeConstants.UnitTypeConstants.igUnitMass, dblMass)

            If MassString <> Nothing Then
                ' check for delimiter as VAL function does not handle ","
                If MassString.Contains(",") Then
                    tmpString = ""
                    For I = 0 To MassString.Length - 1
                        If MassString.Substring(I, 1) = "," Then
                            tmpString = tmpString & "."
                        Else
                            tmpString = tmpString & MassString.Substring(I, 1)
                        End If
                    Next
                    MassString = tmpString
                End If

                'convert the MassString to a double
                MassofPart = CDbl(Val(MassString))

                Debug.Print("Mass = " & MassofPart)
            Else
                MassofPart = dblMass
            End If

            GetMass = 0
P:
            Marshal.FinalReleaseComObject(oSEDoc)
            Marshal.FinalReleaseComObject(oSEApp)
            Garbage()
            oSEDoc = Nothing
            oSEApp = Nothing

        End Function
        Public Function MeasureDistFunctionArgs(ByRef aTypes() As Integer, ByRef aPrompts() As String) As Integer Implements _UserSensor.MeasureDistFunctionArgs

            ReDim aTypes(1)
            ReDim aPrompts(1)

            aTypes(0) = SolidEdgeConstants.seLocateFilterConstants.seLocatePart
            aTypes(1) = SolidEdgeConstants.seLocateFilterConstants.seLocatePart

            aPrompts(0) = "Locate 1st Part"
            aPrompts(1) = "Locate 2nd Part"

            MeasureDistFunctionArgs = 0
        End Function

        Public Function MeasureDist(ByRef objPart1 As Object, ByRef objPart2 As Object, ByRef MinDist As Double) As Integer Implements _UserSensor.MeasureDist
            Dim Point1(2) As Double
            Dim Point2(2) As Double
            Dim oSEApp As Object
            Dim MinDistString, tmpString As String
            Dim I As Integer

            oSEApp = GetObject(, "SolidEdge.Application")

            If oSEApp.ActiveDocument.Type <> SolidEdgeConstants.DocumentTypeConstants.igAssemblyDocument Then
                MsgBox("This is not an assembly document. Exiting Function.")
                MeasureDist = 1
                GoTo P
            End If

            On Error Resume Next
            Call oSEApp.ActiveDocument.MinimumDistance(objPart1, objPart2, MinDist, Point1, Point2)

            If Err.Number Then
                Debug.Print(Err.Description)
                MsgBox("Error executing MinimumDistance Method")
                Err.Clear()
                MeasureDist = 1
                GoTo P
            End If

            'convert MinDist to units in the File Properties/Advanced Units Tab. This is a string
            MinDistString = oSEApp.ActiveDocument.UnitsOfMeasure.FormatUnit(SolidEdgeConstants.UnitTypeConstants.igUnitDistance, MinDist)
            If MinDistString.Contains(",") Then
                tmpString = ""
                For I = 0 To MinDistString.Length - 1
                    If MinDistString.Substring(I, 1) = "," Then
                        tmpString = tmpString & "."
                    Else
                        tmpString = tmpString & MinDistString.Substring(I, 1)
                    End If
                Next
                MinDistString = tmpString
            End If

            MinDist = CDbl(Val(MinDistString))

            MeasureDist = 0
P:
            Marshal.FinalReleaseComObject(oSEApp)
            Garbage()
            oSEApp = Nothing

        End Function

        Public Sub Garbage()

            System.GC.Collect(System.GC.MaxGeneration)
            System.GC.WaitForPendingFinalizers()
            System.GC.Collect(System.GC.MaxGeneration)  'per MS, should do this again to be sure everything is released.

        End Sub

#Region "REGISTRATION"

        ' Code to register/unregister the additional add-in data was derived from Jason Newell (jasonnewell.net)

        ' When Regasm is run on this project, either through IDE or command window, these functions will be called.

        ' Setup the required Solid Edge registry values for an addin that were not automatically
        ' added due to the guid, progid and com visible attributes.
        <ComRegisterFunctionAttribute()> _
        Public Shared Sub RegisterFunction(ByVal t As Type)

            Dim Key As RegistryKey = Registry.ClassesRoot.CreateSubKey("CLSID\{" + t.GUID.ToString() + "}")

            If Not (Key Is Nothing) Then
                Key.CreateSubKey("Implemented Categories\" & "{1a540cc2-eaf8-11d3-b872-00c04f79b2c2}")
                Key.Close()
            End If
        End Sub

        ' Remove any registry values specifically added above.
        <ComUnregisterFunctionAttribute()> _
        Public Shared Sub UnregisterFunction(ByVal t As Type)
            Registry.ClassesRoot.DeleteSubKeyTree("CLSID\{" + t.GUID.ToString() + "}")
        End Sub
#End Region
    End Class
End Namespace