⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 frmtinbuildingburner.frm

📁 arcgis 编程学习事例
💻 FRM
📖 第 1 页 / 共 2 页
字号:
    If (radConstHeight.Value = True) Then
      Dim dHeight As Double
      dHeight = CDbl(txtHeight)
      dHeight = dHeight * dZFact
    End If
    
    Dim dBufDist As Double
    dBufDist = CDbl(txtBuffer)
   
    Dim bAssignTags As Boolean
    
    If (chkTags.Value = vbChecked) Then
      bAssignTags = True
    Else
      bAssignTags = False
    End If
    
    ' Set up cancel tracking and progress bar
    Dim pCancel As ITrackCancel
    Set pCancel = New CancelTracker
    pCancel.CancelOnClick = False
    pCancel.CancelOnKeyPress = True
    Dim pProg As IProgressor
    Set pProg = m_pApp.StatusBar.ProgressBar
    pCancel.Progressor = pProg
    m_pApp.StatusBar.ShowProgressBar "Press ESC to cancel...", 0, 100, 1, True
    
    Dim i As Long
    i = 0
    
    Dim lStepFeatures As Long
    lStepFeatures = lFeatureCount / 100
    
    ' Here's the feature loop
    Do While (Not pInFeature Is Nothing)
          
      i = i + 1
            
      If (i = lStepFeatures) Then
        If (Not pCancel.Continue) Then
          Exit Do
        End If
        i = 0
      End If
            
      Dim pPoly As IPolygon
      Set pPoly = pInFeature.Shape
    
      Dim pGeom As IGeometry
      Set pGeom = pPoly
      pGeom.Project pTinSR
      
      Dim lOID As Long
      lOID = pInFeature.Value(lInxOIDField)
      
      m_pApp.StatusBar.ProgressBar.Message = "OID: " & Str(lOID)
              
      ' Interpolate footprint boundary. This is needed to:
      '   - get its z range for evaluation if building height is relative
      '     to base.
      '   - get correct polygon to buffer for rooftop.
      '   - get a 3D shape to add as a footprint, rather than a 2D shape. With
      '     both footprints and rooftops added as 3D shapes we avoid a performance
      '     penalty that exists when switching between these types (implicit
      '     masking/unmasking of 'super' triangles).
      pSurf.InterpolateShape pPoly, pPoly
                                                
      If (Not pPoly Is Nothing) Then ' could be NULL of outside of surface
        
        ' Get Z range information
        Dim pPrintGeom As IGeometry
        Set pPrintGeom = pPoly
        
        Dim pEnv As IEnvelope
        Set pEnv = pPrintGeom.Envelope
      
        Dim zmin As Double
        Dim zmax As Double
        zmin = pEnv.zmin
        zmax = pEnv.zmax
      
        Dim zRange As Double
        zRange = zmax - zmin
      
        Dim baseHeight As Double
        baseHeight = zmax
              
        ' If height is constant it was already set above, outside of loop.
        ' Otherwise set it to attribute for feature.
        If (radAttribHeight) Then
          dHeight = pInFeature.Value(lInxHeightField)
          dHeight = dHeight * dZFact ' z unit conversion support
        End If
      
        ''''''
        ' Create a buffer inward from the footprint. This will represent the
        ' roof.
        ''''''
                                      
        ' Buffer has some problems with z aware geometry that has negative z
        ' values. Turn off awareness. Fixed at 8.2
        Dim pZAware As IZAware
        Set pZAware = pPoly
        pZAware.ZAware = False

        ' The interpolation process added vertices to the polygon in order to
        ' capture variance in height along the boundary. But because these
        ' densification points are all colinear in 2D they are just more work
        ' for buffer; remove them.
        Dim pPoly2 As IPolygon
        Dim pClone As IClone
        Set pClone = pPoly
        Set pPoly2 = pClone.Clone
        Dim pPolyCurve As IPolycurve
        Set pPolyCurve = pPoly2
        pPolyCurve.Generalize 0.001 ' TODO remove hardcode tolerance
        Dim pTopo As ITopologicalOperator2
        Set pTopo = pPolyCurve
        pTopo.Simplify ' must simplify after generalizing
                
        Dim pBuf As IPolygon
        Set pBuf = pTopo.Buffer(-dBufDist)
        
        ' Restore ZAwareness to our footprint polygon
        pZAware.ZAware = True
                
        ' Generalize the buffer result as building corners end up over sampled
        ' for this application.
        Set pPolyCurve = pBuf
        pPolyCurve.Generalize (dBufDist * 0.1)
                                                    
        ' Add footprint
        If (bAssignTags) Then
          Dim lTag As Long
          lTag = pInFeature.Value(lInxTagField)
          pTinEdit.AddShapeZ pPoly, esriTinHardValueFill, lTag
        Else
          pTinEdit.AddShapeZ pPoly, esriTinHardLine, lTag
        End If
                
        If (chkDeleteNodes.Value = 1) Then
          ' Remove all nodes completely contained by footprint. There is no need
          ' for them. This step could be skipped to make this process run through
          ' faster but overall it's better to remove unnecessary geometry otherwise
          ' you pay the price later.
          DeleteNodesInsidePoly pTinEdit, pPoly2 ' use poly2, this is generalized
        End If
        
        ' Get actual height to use for rooftop
        Dim dAppliedHeight As Double
        If (radHeightAbs) Then
          dAppliedHeight = dHeight
        Else
          dAppliedHeight = baseHeight + dHeight
        End If
                
        ' Add rooftop
        If (bAssignTags) Then
          pTinEdit.AddShape pBuf, esriTinHardReplace, lTag, dAppliedHeight
        Else
          pTinEdit.AddShape pBuf, esriTinHardReplace, 0, dAppliedHeight
        End If
      
      End If
      Set pInFeature = pInCursor.NextFeature
    Loop
                
    m_pApp.StatusBar.HideProgressBar
    
    If (radSaveOld) Then
      pTinEdit.StopEditing True
    Else
      pTinEdit.SaveAs txtOutName
      pTinEdit.StopEditing False
    End If
    
  Else
    Err.Raise -9999, "Add Buildings to TIN", "Unable to place TIN in edit mode."
  End If
  
  Me.MousePointer = vbDefault
  
  m_pMap.DeleteLayer m_pMap.Layer(cboInputTin.ItemData(cboInputTin.ListIndex))
  
  Set pTinLayer = New TinLayer
  Set pTinLayer.Dataset = pTinEdit
  Dim pLayer As ILayer
  Set pLayer = pTinLayer
  Set pDS = pTinEdit
  pLayer.name = pDS.name
  MiscUtil.AddLayer m_pApp, pTinLayer
    
  Unload Me
  
  Exit Sub
EH:
  MsgBox Err.Description, vbCritical, Err.Source
End Sub

' Designed to delete nodes that are completely inside, rather than inside AND
' coincident.
Private Sub DeleteNodesInsidePoly(pTinEdit As ITinEdit, pPoly As IPolygon)

  If (pTinEdit.IsInEditMode) Then
    Dim pTinSel As ITinSelection
    Set pTinSel = pTinEdit
    pTinSel.ClearSelection esriTinNode
    pTinSel.SelectByArea esriTinNode, pPoly, False, True, esriTinSelectionNew
    
    ' Now determine which of these are disjoint (non-coincident with boundary)
    Dim pEnum As IEnumTinNode
    Set pEnum = pTinSel.GetSelection(esriTinNode)
    
    Dim pNode As ITinNode
    Set pNode = New TinNode
    
    pEnum.QueryNext pNode
    
    Dim pPoint As IPoint
    Set pPoint = New Point
    
    Dim pRelOp As IRelationalOperator
    Set pRelOp = pPoly
    
    Dim pLongArray As ILongArray
    Set pLongArray = New LongArray
    
    Do While (Not pNode.IsEmpty)
      pNode.QueryAsPoint pPoint
      If (Not pRelOp.Touches(pPoint)) Then
        pLongArray.Add pNode.Index
      End If
      pEnum.QueryNext pNode
    Loop
    
    Dim pCount As Long
    pCount = pLongArray.Count
    
    If (pCount > 0) Then
      pTinSel.ClearSelection esriTinNode
      Dim i As Long
      For i = 0 To pCount - 1
        pTinSel.SetSelected pLongArray.Element(i), esriTinNode, esriTinSelectionAdd
      Next i
      pTinEdit.DeleteSelectedNodes
    End If
  End If
  
End Sub

Private Sub Form_Load()
  On Error GoTo EH
  
  ' Height conversion options
  cboZFactor.AddItem "none"
  cboZFactor.AddItem "feet to meters"
  cboZFactor.AddItem "meters to feet"
  cboZFactor.ListIndex = 0
  
  ' Get default output name for 'Save As' option.
  txtOutName = dbUtil.GetDefaultOutWorkspaceName
  txtOutName = txtOutName & "\" & dbUtil.GetUniqueFileName(txtOutName, "tin")
  
  ' Load up the input TIN and polygon combo boxes
  Dim lyrIndex As Long
  For lyrIndex = 0 To (m_pMap.LayerCount - 1)
    Dim pLayer As ILayer
    Set pLayer = m_pMap.Layer(lyrIndex)
    If (TypeOf pLayer Is ITinLayer) Then
      cboInputTin.AddItem pLayer.name
      cboInputTin.ItemData(cboInputTin.ListCount - 1) = lyrIndex
    ElseIf (TypeOf pLayer Is IFeatureLayer) Then
      Dim pFlayer As IFeatureLayer
      Set pFlayer = pLayer
      Dim pFC As IFeatureClass
      Set pFC = pFlayer.FeatureClass
      If (pFC.shapeType = esriGeometryPolygon) Then
        cboInputPoly.AddItem pLayer.name
        cboInputPoly.ItemData(cboInputPoly.ListCount - 1) = lyrIndex
      End If
    End If
  Next lyrIndex
  
  If (cboInputTin.ListCount > 0) Then
    cboInputTin.ListIndex = 0
  End If
  
  If (cboInputPoly.ListCount > 0) Then
    cboInputPoly.ListIndex = 0
  End If
  
  Exit Sub
EH:
  MsgBox Err.Description, vbCritical, Err.Source
End Sub

Private Sub SetInputTin()
  If (cboInputTin.ItemData(cboInputTin.ListIndex) >= 0) Then ' doc layer source
    Dim pLayer As ITinLayer
    Set pLayer = m_pMap.Layer(cboInputTin.ItemData(cboInputTin.ListIndex))
    Set m_pInputTin = pLayer.Dataset
  End If
End Sub

Private Sub SetInputPoly()
  If (cboInputPoly.ItemData(cboInputPoly.ListIndex) >= 0) Then ' doc layer source
    Dim pLayer As IFeatureLayer
    Set pLayer = m_pMap.Layer(cboInputPoly.ItemData(cboInputPoly.ListIndex))
    Set m_pInFClass = pLayer.FeatureClass
  End If
  
  LoadPolyFields
End Sub

Private Sub LoadPolyFields()

  cboElevFields.Clear
  cboBldgID.Clear
  
  Dim pFields As IFields
  Set pFields = m_pInFClass.Fields
  Dim pField As IField
  
  Dim lDefElevIndex As Long
  lDefElevIndex = -1
  
  Dim i As Long
  For i = 0 To (pFields.FieldCount - 1)
    Set pField = pFields.Field(i)
    If (pField.Type = esriFieldTypeDouble Or pField.Type = esriFieldTypeInteger Or _
        pField.Type = esriFieldTypeSingle Or pField.Type = esriFieldTypeSmallInteger) Then
      cboElevFields.AddItem pField.name
      cboElevFields.ItemData(cboElevFields.ListCount - 1) = i
      Dim sName As String
      sName = UCase(pField.name)
      If sName = "ELEVATION" Or sName = "ELEV" Or sName = "SPOT" Or _
         sName = "HEIGHT" Or sName = "HEIGHT_AG" Or sName = "Z" Then
        lDefElevIndex = cboElevFields.ListCount - 1
      End If
      cboBldgID.AddItem pField.name
      cboBldgID.ItemData(cboBldgID.ListCount - 1) = i
      cboTagFields.AddItem pField.name
      cboTagFields.ItemData(cboBldgID.ListCount - 1) = i
    End If
  Next i
  
  If (cboElevFields.ListCount > 0) Then
    If (lDefElevIndex > -1) Then
      cboElevFields.ListIndex = lDefElevIndex
      radAttribHeight.Value = True
    Else
      cboElevFields.ListIndex = 0
    End If
  End If
    
  If (cboBldgID.ListCount > 0) Then
    cboBldgID.ListIndex = 0
  End If

  If (cboTagFields.ListCount > 0) Then
    cboTagFields.ListIndex = 0
  End If

End Sub

Private Sub Form_Unload(Cancel As Integer)
  Set m_pApp = Nothing
  Set m_pMap = Nothing
  Set m_pInputTin = Nothing
  Set m_pInFClass = Nothing
End Sub

Private Function ValidateInputs() As Boolean
  On Error GoTo EH
  
  ValidateInputs = False
  
  Dim sOutDir As String
  Dim sOutName As String
  If (Not dbUtil.ResolveOutputTinName(txtOutName, sOutDir, sOutName)) Then
    If (dbUtil.GetErrorCode = 1) Then
      MsgBox dbUtil.GetErrorMessage, vbCritical
    End If
    Exit Function
  End If
  
  If (cboZFactor.ListIndex = -1) Then
    If (Not IsNumeric(cboZFactor)) Then
      MsgBox "The conversion factor provided is not a valid number.", vbInformation
      Exit Function
    ElseIf (CDbl(cboZFactor) = 0#) Then
      MsgBox "The conversion factor provided can not be equal to 0.0"
      Exit Function
    End If
  End If
    
  Dim d As Double
  If (radConstHeight) Then
    If (Not IsNumeric(txtHeight)) Then
      MsgBox "Building height specified is not a valid number.", vbInformation
      Exit Function
    Else
      d = CStr(txtHeight)
      If (d <= 0) Then
        MsgBox "Building height needs to be greater than 0.0.", vbInformation
        Exit Function
      End If
    End If
  End If
  
  If (Not IsNumeric(txtBuffer)) Then
    MsgBox "The rooftop buffer specified is not a valid number.", vbInformation
    Exit Function
  Else
    d = CStr(txtBuffer)
    If (d <= 0) Then
      MsgBox "Rooftop buffer needs to be greater than 0.0.", vbInformation
      Exit Function
    End If
  End If
    
  ValidateInputs = True
  
  Exit Function
EH:
  MsgBox Err.Description, vbCritical, Err.Source
End Function

Private Sub txtHeight_GotFocus()
  radConstHeight.Value = True
End Sub

Private Sub txtOutName_GotFocus()
  radSaveNew = True
End Sub

Public Sub StatusBarMessage(sMsg)
  m_pApp.StatusBar.Message(0) = sMsg
  DoEvents
End Sub

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -