No it doesn't have to be hosted on another topo surface or pre-existing. It can be created on something that has a surface reference but not a datum element such as level. The below creates a randomised topo and places spot elevations on it. The spot elevations are copied from a single spot elevation hosted on a direct shape which is created for the purpose and deleted at the end.
Private Function Obj_210906a(ByVal commandData As Autodesk.Revit.UI.ExternalCommandData,
ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Result
Dim UIDoc As UIDocument = commandData.Application.ActiveUIDocument
If UIDoc Is Nothing Then Return Result.Cancelled Else
Dim IntDoc As Document = UIDoc.Document
Dim V As View = UIDoc.ActiveGraphicalView
Dim SpotEl As Element = Nothing
Dim DS As DirectShape = Nothing
Dim Topo As Element = Nothing
Dim Pts As New List(Of XYZ)
Dim Nnum As Integer = 60
Dim Mnum As Integer = 40
Dim RND As New Random
Dim Range As Integer() = New Integer() {Nnum / 3, Mnum / 3}
Dim HeightLimits As Double() = New Double(1) {2 / 0.3048, 1 / 0.3048}
For X = 0 To Range(0) - 1
For Y = 0 To Range(1) - 1
Dim H As Double = HeightLimits(0) + (RND.NextDouble() * (HeightLimits(1) - HeightLimits(0)))
Dim Pt As New XYZ((X * 3) / 0.3048, (Y * 3) / 0.3048, H)
Pts.Add(Pt)
Next
Next
Using TR0 As New Transaction(IntDoc, "Create random topo")
If TR0.Start = TransactionStatus.Started Then
Topo = TopographySurface.Create(IntDoc, Pts)
V.SetCategoryHidden(New ElementId(BuiltInCategory.OST_Topography), False)
TR0.Commit()
End If
End Using
Using Tg As New TransactionGroup(IntDoc, "Add topo spot elevation")
If Tg.Start = TransactionStatus.Started Then
'Create direct shape to host spot elevation
Using TR0 As New Transaction(IntDoc, "Spot elev")
If TR0.Start = TransactionStatus.Started Then
Dim PL As Plane = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero)
Dim SKP As SketchPlane = SketchPlane.Create(IntDoc, PL)
DS = DirectShape.CreateElement(IntDoc, New ElementId(BuiltInCategory.OST_GenericModel))
Dim A0 As Arc = Arc.Create(PL, 1, 0, Math.PI)
Dim A1 As Arc = Arc.Create(PL, 1, Math.PI, 2 * Math.PI)
Dim CL As New CurveLoop
CL.Append(A0)
CL.Append(A1)
Dim S As Solid = GeometryCreationUtilities.CreateExtrusionGeometry({CL}.ToList, -XYZ.BasisZ, 0.25)
DS.SetShape(New GeometryObject() {S}.ToList)
TR0.Commit()
End If
End Using
'Add spot elevation to top face of newly created direct shape.
Using TR1 As New Transaction(IntDoc, "Spot elev")
If TR1.Start = TransactionStatus.Started Then
Dim GeomEl As GeometryElement = DS.Geometry(New Options With {.DetailLevel = ViewDetailLevel.Fine, .ComputeReferences = True})
Dim S0 As Solid = GeomEl.Where(Function(x) x.GetType = GetType(Solid)).Cast(Of Solid).Where(Function(x) x.Volume > 0).FirstOrDefault
Dim TF As Face = Nothing
For i = 0 To S0.Faces.Size - 1
Dim F As PlanarFace = TryCast(S0.Faces.Item(i), PlanarFace)
If F Is Nothing Then Continue For Else
If F.FaceNormal.IsAlmostEqualTo(XYZ.BasisZ) Then
TF = F
End If
Next
Dim P As XYZ = XYZ.Zero
SpotEl = IntDoc.Create.NewSpotElevation(V, TF.Reference, P, P, P, P, False)
TR1.Commit()
End If
End Using
'Copy onto topo
Using TR2 As New Transaction(IntDoc, "Spot elev")
If TR2.Start = TransactionStatus.Started Then
For Each GP As XYZ In Pts
Dim Els As List(Of ElementId) = ElementTransformUtils.CopyElement(IntDoc, SpotEl.Id, GP)
Next
IntDoc.Delete(New ElementId() {DS.Id, SpotEl.Id}.ToList)
TR2.Commit()
End If
End Using
Tg.Assimilate()
End If
End Using
Return Result.Succeeded
End Function
In a new empty project you should then end up with something like the below:
