Skip to content

Commit

Permalink
added leaflabels, but deactivated them for now, bypassed erroneous pa…
Browse files Browse the repository at this point in the history
…tch filter for AnnotationQuery, added meshlab startup to Query.ipynb
  • Loading branch information
ThomasOrtner committed Nov 26, 2024
1 parent fa3121c commit ee65f25
Show file tree
Hide file tree
Showing 9 changed files with 511,236 additions and 64,861 deletions.
23 changes: 11 additions & 12 deletions src/PRo3D.Core/Queries/AnnotationQuery.fs
Original file line number Diff line number Diff line change
Expand Up @@ -55,38 +55,37 @@ type QueryFunctions =

module AnnotationQuery =

let queryFunctionsFromPointsOnPlane (heightRange : Range1d) (points : seq<V3d>) =
let queryFunctionsFromPointsOnPlane (heightRange : Range1d) (points : seq<V3d>) : QueryFunctions =

let lineRegression =
let linearRegression =
let regression = new LinearRegression3d(points)
regression.TryGetRegressionInfo()

let plane =
match lineRegression with
match linearRegression with
| Some p -> Plane3d(p.Normal.Normalized, p.Center)
| None ->
Log.warn "[Queries] line regression failed, using fallback"
CSharpUtils.PlaneFitting.Fit(points |> Seq.toArray)
| Some p -> Plane3d(p.Normal.Normalized, p.Center) //p.Plane

let projectedPolygon =
points
|> Seq.map (fun p -> plane.ProjectToPlaneSpace p)
|> Polygon2d

let projectedPolygon = projectedPolygon.ComputeConvexHullIndexPolygon().ToPolygon2d()



let intersectsQuery (globalBoundingBox : Box3d) =
let p2w = plane.GetPlaneToWorld()
let pointsInWorld = projectedPolygon.Points |> Seq.map (fun p -> p2w.TransformPos(V3d(p,0.0)))
pointsInWorld |> Seq.exists (fun p -> globalBoundingBox.Contains p)
true
//let p2w = plane.GetPlaneToWorld()
//let pointsInWorld = projectedPolygon.Points |> Seq.map (fun p -> p2w.TransformPos(V3d(p,0.0)))
//pointsInWorld |> Seq.exists (fun p -> globalBoundingBox.Contains p)


let globalCoordWithinQuery (p : V3d) =
let projected = plane.ProjectToPlaneSpace(p)
let h = plane.Height(p)
projectedPolygon.Contains(projected) && heightRange.Contains(h)


{
boxIntersectsQuery = intersectsQuery
globalWorldPointWithinQuery = globalCoordWithinQuery
Expand All @@ -96,7 +95,7 @@ module AnnotationQuery =
(heightRange : Range1d)
(annotation : Annotation)
: QueryFunctions =

let corners = annotation.points |> IndexList.toSeq
let segmentPoints = annotation.segments |> Seq.collect (fun s -> s.points)
let points = Seq.concat [corners; segmentPoints]
Expand Down
1 change: 1 addition & 0 deletions src/PRo3D.Core/SceneObjectsApp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ module SceneObjectsUtils =
picking = Picking.NoPicking
isObj = true
opcScene = None
leafLabels = HashSet.empty
}


Expand Down
1 change: 1 addition & 0 deletions src/PRo3D.Core/Surface-Model.fs
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,7 @@ type SgSurface = {
sceneGraph : ISg
picking : Picking
opcScene : Option<Aardvark.GeoSpatial.Opc.Configurations.OpcScene>
leafLabels : HashSet<string * Box3d>

[<NonAdaptive>]
isObj : bool
Expand Down
83 changes: 57 additions & 26 deletions src/PRo3D.Core/Surface/Surface.Sg.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ open System.IO
open Aardvark.Base
open Aardvark.Base.Ag
open FSharp.Data.Adaptive
open FSharp.Data.Adaptive.Operators
open Aardvark.Rendering
open Aardvark.SceneGraph
open Aardvark.SceneGraph.IO
Expand All @@ -27,6 +28,7 @@ open PRo3D.Core
open PRo3D.Core.Surface
open Aardvark.GeoSpatial.Opc.PatchLod
open Aardvark.Base.Ag
open Aardvark.Rendering.Text

module FootprintSg =
open Aardvark.SceneGraph.Sg
Expand Down Expand Up @@ -302,13 +304,33 @@ module Sg =
let createSgSurface
(scene : OpcScene)
(s : Surface)
sg
(sg : ISg)
(bb : Box3d)
(kd : HashMap<Box3d,KdTrees.Level0KdTree>) =

let pose = Pose.translate V3d.Zero // bb.Center
let trafo = { TrafoController.initial with pose = pose; previewTrafo = Pose.toTrafo pose; mode = TrafoMode.Local }


let patchHierarchies =
scene.patchHierarchies
|> Seq.map Prinziple.registerIfZipped
|> Seq.map (fun x ->
PatchHierarchy.load Serialization.binarySerializer.Pickle Serialization.binarySerializer.UnPickle (OpcPaths x)
)
|> Seq.toList

let leafLabels =
patchHierarchies
|> List.map (fun h -> h.tree |> QTree.getLeaves)
|> Seq.concat
|> Seq.map (fun p -> (p.info.Name, p.info.GlobalBoundingBox))
|> HashSet.ofSeq



Log.line "[SgSurface] %A" leafLabels

let sgSurface = {
surface = s.guid
sceneGraph = sg
Expand All @@ -317,6 +339,7 @@ module Sg =
trafo = trafo
isObj = false
opcScene = Some scene
leafLabels = leafLabels
//transformation = Init.Transformations
}
sgSurface
Expand Down Expand Up @@ -369,7 +392,9 @@ module Sg =

sgSurfaces

let viewHomePosition (model:AdaptiveSurfaceModel) =


let viewHomePosition (model:AdaptiveSurfaceModel) : ISg<'a> =
let point =
aset{
let! guid = model.surfaces.singleSelectLeaf
Expand Down Expand Up @@ -397,33 +422,39 @@ module Sg =
}|> Aardvark.UI.``F# Sg``.Sg.set
Aardvark.UI.``F# Sg``.Sg.ofList [point]

let viewPatchCenters (model:AdaptiveSurfaceModel) =
let point =
aset{
let! guid = model.surfaces.singleSelectLeaf
let fail = Sg.empty
let viewLeafLabels
(near : aval<float>)
(fov : aval<float>)
(view : aval<CameraView>)
(model : AdaptiveSurfaceModel)
: ISg<'a> =

let points =
aset{
let! guid = model.surfaces.singleSelectLeaf
match guid with
| Some i ->
let! exists = (model.surfaces.flat |> AMap.keys) |> ASet.contains i
if exists then
let leaf = model.surfaces.flat |> AMap.find i
let! surf = leaf
let x =
match surf with
| AdaptiveSurfaces s -> s
| _ -> surf |> sprintf "wrong type %A; expected AdaptiveSurfaces" |> failwith

let! hpos = x.homePosition
match hpos with
| Some p -> yield Sg.dot (AVal.constant C4b.Yellow) (AVal.constant 3.0) (AVal.constant p.Location)
| None -> yield fail
else
yield fail
| Some surfaceId ->
let! selectedSgSurface = (model.sgSurfaces |> AMap.tryFind surfaceId)
match selectedSgSurface with
| Some s ->
let labels =
s.leafLabels
|> ASet.filter(fun (name, box) -> true)
|> ASet.map (fun (name, box) ->
let pos = box.Center
(PRo3D.Base.Sg.text (view) (near) (fov) ~~pos (~~pos |> AVal.map Trafo3d.Translation) ~~0.05 ~~name)
|> Sg.andAlso (Sg.dot (AVal.constant C4b.VRVisGreen) (AVal.constant 5.0) (~~pos))
)
yield! labels
| None -> yield Sg.empty
| None ->
yield fail
}|> Aardvark.UI.``F# Sg``.Sg.set
Aardvark.UI.``F# Sg``.Sg.ofList [point]
yield Sg.empty
}

points
|> ASet.map Sg.noEvents
|> Sg.set




Expand Down
2 changes: 2 additions & 0 deletions src/PRo3D.Core/Surface/SurfaceApp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ module SurfaceUtils =
picking = Picking.KdTree(kdTrees |> HashMap.ofList) //Picking.PickMesh meshes
isObj = true
opcScene = None
leafLabels = FSharp.Data.Adaptive.HashSet.empty
//transformation = Init.Transformations
}

Expand Down Expand Up @@ -648,6 +649,7 @@ module SurfaceUtils =
picking = Picking.KdTree(kdTrees |> HashMap.ofList)
isObj = true
opcScene = None
leafLabels = FSharp.Data.Adaptive.HashSet.empty
//transformation = Init.Transformations
}

Expand Down
8 changes: 6 additions & 2 deletions src/PRo3D.Viewer/RemoteApi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -675,15 +675,19 @@ module RemoteApi =

let queryAnnotationAsObj (api : Api) =

let toResult (frame : OutputReferenceFrame) (geometryType : OutputGeometryType) (results : QueryResults) =
let toResult
(frame : OutputReferenceFrame)
(geometryType : OutputGeometryType)
(results : QueryResults) =

let s = PRo3D.Base.AnnotationQuery.queryResultsToObj frame geometryType results
Successful.OK s

queryAnnotation api toResult

let queryAnnotationAsJson (api : Api) =

let toJson (_ : OutputReferenceFrame) (_ : OutputGeometryType) (results : QueryResults) =
let toJson (_ : OutputReferenceFrame) (_ : OutputGeometryType) (results : QueryResults) =
let s = PRo3D.Base.QueryApi.hitsToJson results //todo: also add frame
Successful.OK s

Expand Down
4 changes: 4 additions & 0 deletions src/PRo3D.Viewer/Viewer/Viewer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1883,6 +1883,9 @@ module ViewerApp =

let homePosition =
Sg.viewHomePosition m.scene.surfacesModel

let leafLabels =
Sg.viewLeafLabels ~~0.01 ~~60.0 m.navigation.camera.view m.scene.surfacesModel

let viewPlans =
ViewPlanApp.Sg.view
Expand Down Expand Up @@ -1947,6 +1950,7 @@ module ViewerApp =
refSystem;
viewPlans;
homePosition;
// leafLabels;
// solText;
annotationTexts |> Sg.noEvents
heightValidation
Expand Down
45 changes: 28 additions & 17 deletions src/Tests/Query.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,21 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3b017634-146d-4712-b4f4-ef69947f55db\n"
"3d140ab5-498b-4ab4-a00f-1b98094b19b0\n"
]
}
],
"source": [
"import requests\n",
"import json\n",
"import subprocess\n",
"\n",
"\n",
"url = \"http://localhost:4321/api/queries/findAnnotation\"\n",
Expand All @@ -43,26 +44,14 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'annotationId': '3b017634-146d-4712-b4f4-ef69947f55db', 'queryAttributes': [], 'distanceToPlane': 100.0, 'outputReferenceFrame': 'global'}\n"
]
},
{
"ename": "HTTPError",
"evalue": "400 Client Error: Bad Request for url: http://localhost:4321/api/queries/queryAnnotationAsObj",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mHTTPError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[1;32mIn[10], line 10\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[38;5;28mprint\u001b[39m(payload)\n\u001b[0;32m 9\u001b[0m response \u001b[38;5;241m=\u001b[39m requests\u001b[38;5;241m.\u001b[39mpost(url, json\u001b[38;5;241m=\u001b[39mpayload)\n\u001b[1;32m---> 10\u001b[0m response\u001b[38;5;241m.\u001b[39mraise_for_status() \n\u001b[0;32m 11\u001b[0m file \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mopen\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m./obj.obj\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mw\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 12\u001b[0m file\u001b[38;5;241m.\u001b[39mwrite(response\u001b[38;5;241m.\u001b[39mtext)\n",
"File \u001b[1;32mc:\\Users\\ortne\\anaconda3\\Lib\\site-packages\\requests\\models.py:1024\u001b[0m, in \u001b[0;36mResponse.raise_for_status\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 1019\u001b[0m http_error_msg \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m 1020\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstatus_code\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m Server Error: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mreason\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m for url: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39murl\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 1021\u001b[0m )\n\u001b[0;32m 1023\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m http_error_msg:\n\u001b[1;32m-> 1024\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m HTTPError(http_error_msg, response\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m)\n",
"\u001b[1;31mHTTPError\u001b[0m: 400 Client Error: Bad Request for url: http://localhost:4321/api/queries/queryAnnotationAsObj"
"{'annotationId': '3d140ab5-498b-4ab4-a00f-1b98094b19b0', 'queryAttributes': [], 'distanceToPlane': 100.0, 'outputReferenceFrame': 'global', 'outputGeometryType': 'pointcloud'}\n"
]
}
],
Expand All @@ -78,11 +67,33 @@
"print(payload)\n",
"response = requests.post(url, json=payload)\n",
"response.raise_for_status() \n",
"file = open(\"./obj.obj\", \"w\")\n",
"filename = \"./695.obj\"\n",
"file = open(filename, \"w\")\n",
"file.write(response.text)\n",
"file.close()"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"MeshLab started successfully.\n"
]
}
],
"source": [
"try:\n",
" subprocess.Popen([\"C:/Program Files/vcg/MeshLab/meshlab.exe\", filename])\n",
" print(\"MeshLab started successfully.\")\n",
"except FileNotFoundError:\n",
" print(\"MeshLab executable not found. Please ensure it is installed and in your system PATH.\")"
]
},
{
"cell_type": "code",
"execution_count": 37,
Expand Down
Loading

0 comments on commit ee65f25

Please sign in to comment.