@@ -304,6 +304,301 @@ int splitLimit
304304 ;
305305
306306
307+ if ( lodKd != null )
308+ {
309+ storage . Add ( kdId , lodKd . Data ) ;
310+ data = data . Add ( Durable . Octree . PointRkdTreeFDataReference , kdId ) ;
311+ }
312+ if ( lodCs != null )
313+ {
314+ storage . Add ( csId , lodCs ) ;
315+ data = data . Add ( Durable . Octree . Colors4bReference , csId ) ;
316+ }
317+ if ( lodNs != null )
318+ {
319+ storage . Add ( nsId , lodNs ) ;
320+ data = data . Add ( Durable . Octree . Normals3fReference , nsId ) ;
321+ }
322+ if ( lodIs != null )
323+ {
324+ storage . Add ( isId , lodIs ) ;
325+ data = data . Add ( Durable . Octree . Intensities1iReference , isId ) ;
326+ }
327+ if ( lodKs != null )
328+ {
329+ storage . Add ( ksId , lodKs ) ;
330+ data = data . Add ( Durable . Octree . Classifications1bReference , ksId ) ;
331+ }
332+
333+ // MinTreeDepth MaxTreeDepth SubNodeIds??
334+ return new PointSetNode ( data , storage , writeToStore : true ) ;
335+ }
336+ }
337+ }
338+ /// <summary>
339+ /// Returns new tree with all points deleted which are inside. Additionally tests visited points using classifications.
340+ /// </summary>
341+ public static IPointCloudNode DeleteWithClassifications ( this IPointCloudNode root ,
342+ Func < IPointCloudNode , bool > isNodeFullyInside ,
343+ Func < IPointCloudNode , bool > isNodeFullyOutside ,
344+ Func < V3d , byte , bool > isPositionInside ,
345+ Storage storage , CancellationToken ct ,
346+ int splitLimit
347+ )
348+ {
349+ if ( root == null ) return null ;
350+
351+ if ( root is FilteredNode f )
352+ {
353+ if ( f . Filter is ISpatialFilter filter )
354+ {
355+ bool remove ( IPointCloudNode n ) => filter . IsFullyInside ( n ) && isNodeFullyInside ( n ) ;
356+ bool keep ( IPointCloudNode n ) => filter . IsFullyOutside ( n ) || isNodeFullyOutside ( n ) ;
357+ bool contains ( V3d pt , byte c ) => filter . Contains ( pt ) && isPositionInside ( pt , c ) ;
358+ var res = f . Node . DeleteWithClassifications ( remove , keep , contains , storage , ct , splitLimit ) ;
359+ return FilteredNode . Create ( res , f . Filter ) ;
360+ }
361+ else
362+ {
363+ throw new NotImplementedException ( "cannot delete on PointCloud with non-spatial filter" ) ;
364+ }
365+ }
366+
367+
368+ if ( isNodeFullyInside ( root ) ) return null ;
369+ if ( isNodeFullyOutside ( root ) )
370+ {
371+ if ( ! root . IsMaterialized )
372+ {
373+ root = root . Materialize ( ) ;
374+ }
375+ return root ;
376+ }
377+
378+ if ( root . IsLeaf )
379+ {
380+ var ps = root . HasPositions ? new List < V3f > ( ) : null ;
381+ var cs = root . HasColors ? new List < C4b > ( ) : null ;
382+ var ns = root . HasNormals ? new List < V3f > ( ) : null ;
383+ var js = root . HasIntensities ? new List < int > ( ) : null ;
384+ var ks = root . HasClassifications ? new List < byte > ( ) : null ;
385+ var oldPs = root . Positions ? . Value ;
386+ var oldCs = root . Colors ? . Value ;
387+ var oldNs = root . Normals ? . Value ;
388+ var oldIs = root . Intensities ? . Value ;
389+ var oldKs = root . Classifications ? . Value ;
390+ var bbabs = Box3d . Invalid ;
391+ var bbloc = Box3f . Invalid ;
392+
393+ for ( var i = 0 ; i < oldPs . Length ; i ++ )
394+ {
395+ var pabs = ( V3d ) oldPs [ i ] + root . Center ;
396+
397+ if ( oldKs == null ) { throw new ArgumentException ( "Can not call DeleteWithClassifications for point cloud without classifications. edd662d4-1656-4800-96e0-cbe7856ab00c" ) ; }
398+ var oldK = oldKs [ i ] ;
399+
400+ if ( ! isPositionInside ( pabs , oldK ) )
401+ {
402+ if ( oldPs != null ) ps . Add ( oldPs [ i ] ) ;
403+ if ( oldCs != null ) cs . Add ( oldCs [ i ] ) ;
404+ if ( oldNs != null ) ns . Add ( oldNs [ i ] ) ;
405+ if ( oldIs != null ) js . Add ( oldIs [ i ] ) ;
406+ if ( oldKs != null ) ks . Add ( oldKs [ i ] ) ;
407+ bbabs . ExtendBy ( pabs ) ;
408+ bbloc . ExtendBy ( oldPs [ i ] ) ;
409+ }
410+ }
411+
412+ if ( ps . Count == 0 ) return null ;
413+
414+ var psa = ps . ToArray ( ) ;
415+ var newId = Guid . NewGuid ( ) ;
416+ var kd = psa . Length < 1 ? null : psa . BuildKdTree ( ) ;
417+
418+ Guid psId = Guid . NewGuid ( ) ;
419+ Guid kdId = kd != null ? Guid . NewGuid ( ) : Guid . Empty ;
420+ Guid csId = cs != null ? Guid . NewGuid ( ) : Guid . Empty ;
421+ Guid nsId = ns != null ? Guid . NewGuid ( ) : Guid . Empty ;
422+ Guid isId = js != null ? Guid . NewGuid ( ) : Guid . Empty ;
423+ Guid ksId = ks != null ? Guid . NewGuid ( ) : Guid . Empty ;
424+
425+ storage . Add ( psId , psa ) ;
426+
427+ var data = ImmutableDictionary < Durable . Def , object > . Empty
428+ . Add ( Durable . Octree . NodeId , newId )
429+ . Add ( Durable . Octree . Cell , root . Cell )
430+ . Add ( Durable . Octree . BoundingBoxExactGlobal , bbabs )
431+ . Add ( Durable . Octree . BoundingBoxExactLocal , bbloc )
432+ . Add ( Durable . Octree . PositionsLocal3fReference , psId )
433+ . Add ( Durable . Octree . PointCountCell , ps . Count )
434+ . Add ( Durable . Octree . PointCountTreeLeafs , ( long ) ps . Count )
435+ . Add ( Durable . Octree . MaxTreeDepth , 0 )
436+ . Add ( Durable . Octree . MinTreeDepth , 0 )
437+ ;
438+
439+
440+ if ( kd != null )
441+ {
442+ storage . Add ( kdId , kd . Data ) ;
443+ data = data . Add ( Durable . Octree . PointRkdTreeFDataReference , kdId ) ;
444+ }
445+ if ( cs != null )
446+ {
447+ storage . Add ( csId , cs . ToArray ( ) ) ;
448+ data = data . Add ( Durable . Octree . Colors4bReference , csId ) ;
449+ }
450+ if ( ns != null )
451+ {
452+ storage . Add ( nsId , ns . ToArray ( ) ) ;
453+ data = data . Add ( Durable . Octree . Normals3fReference , nsId ) ;
454+ }
455+ if ( js != null )
456+ {
457+ storage . Add ( isId , js . ToArray ( ) ) ;
458+ data = data . Add ( Durable . Octree . Intensities1iReference , isId ) ;
459+ }
460+ if ( ks != null )
461+ {
462+ storage . Add ( ksId , ks . ToArray ( ) ) ;
463+ data = data . Add ( Durable . Octree . Classifications1bReference , ksId ) ;
464+ }
465+
466+ // MinTreeDepth MaxTreeDepth SubNodeIds??
467+ return new PointSetNode ( data , storage , writeToStore : true ) ;
468+ }
469+ else
470+ {
471+ var subnodes = root . Subnodes . Map ( ( r ) => r ? . Value ? . DeleteWithClassifications ( isNodeFullyInside , isNodeFullyOutside , isPositionInside , storage , ct , splitLimit ) ) ;
472+ var pointCountTree = subnodes . Sum ( ( n ) => n != null ? n . PointCountTree : 0 ) ;
473+ if ( pointCountTree == 0 )
474+ {
475+ return null ;
476+ }
477+ else if ( pointCountTree <= splitLimit )
478+ {
479+ var psabs = root . HasPositions ? new List < V3d > ( ) : null ;
480+ var cs = root . HasColors ? new List < C4b > ( ) : null ;
481+ var ns = root . HasNormals ? new List < V3f > ( ) : null ;
482+ var js = root . HasIntensities ? new List < int > ( ) : null ;
483+ var ks = root . HasClassifications ? new List < byte > ( ) : null ;
484+ foreach ( var c in subnodes )
485+ {
486+ if ( c != null ) MergeExtensions . CollectEverything ( c , psabs , cs , ns , js , ks ) ;
487+ }
488+ Debug . Assert ( psabs . Count == pointCountTree ) ;
489+ var psa = psabs . MapToArray ( ( p ) => ( V3f ) ( p - root . Center ) ) ;
490+ var kd = psa . Length < 1 ? null : psa . BuildKdTree ( ) ;
491+
492+
493+ Guid psId = Guid . NewGuid ( ) ;
494+ Guid kdId = kd != null ? Guid . NewGuid ( ) : Guid . Empty ;
495+ Guid csId = cs != null ? Guid . NewGuid ( ) : Guid . Empty ;
496+ Guid nsId = ns != null ? Guid . NewGuid ( ) : Guid . Empty ;
497+ Guid isId = js != null ? Guid . NewGuid ( ) : Guid . Empty ;
498+ Guid ksId = ks != null ? Guid . NewGuid ( ) : Guid . Empty ;
499+
500+ var bbabs = new Box3d ( psabs ) ;
501+
502+ var newId = Guid . NewGuid ( ) ;
503+ storage . Add ( psId , psa ) ;
504+
505+ var data = ImmutableDictionary < Durable . Def , object > . Empty
506+ . Add ( Durable . Octree . NodeId , newId )
507+ . Add ( Durable . Octree . Cell , root . Cell )
508+ . Add ( Durable . Octree . BoundingBoxExactGlobal , bbabs )
509+ . Add ( Durable . Octree . BoundingBoxExactLocal , ( Box3f ) ( bbabs - root . Center ) )
510+ . Add ( Durable . Octree . PositionsLocal3fReference , psId )
511+ . Add ( Durable . Octree . PointCountCell , ( int ) pointCountTree )
512+ . Add ( Durable . Octree . PointCountTreeLeafs , pointCountTree )
513+ . Add ( Durable . Octree . MaxTreeDepth , 0 )
514+ . Add ( Durable . Octree . MinTreeDepth , 0 )
515+ ;
516+ if ( kd != null )
517+ {
518+ storage . Add ( kdId , kd . Data ) ;
519+ data = data . Add ( Durable . Octree . PointRkdTreeFDataReference , kdId ) ;
520+ }
521+ if ( cs != null )
522+ {
523+ storage . Add ( csId , cs . ToArray ( ) ) ;
524+ data = data . Add ( Durable . Octree . Colors4bReference , csId ) ;
525+ }
526+ if ( ns != null )
527+ {
528+ storage . Add ( nsId , ns . ToArray ( ) ) ;
529+ data = data . Add ( Durable . Octree . Normals3fReference , nsId ) ;
530+ }
531+ if ( js != null )
532+ {
533+ storage . Add ( isId , js . ToArray ( ) ) ;
534+ data = data . Add ( Durable . Octree . Intensities1iReference , isId ) ;
535+ }
536+ if ( ks != null )
537+ {
538+ storage . Add ( ksId , ks . ToArray ( ) ) ;
539+ data = data . Add ( Durable . Octree . Classifications1bReference , ksId ) ;
540+ }
541+
542+ // MinTreeDepth MaxTreeDepth SubNodeIds??
543+ return new PointSetNode ( data , storage , writeToStore : true ) ;
544+ }
545+ else
546+ {
547+ var bbabs = new Box3d ( subnodes . Map ( n => n != null ? n . BoundingBoxExactGlobal : Box3d . Invalid ) ) ;
548+ var subids = subnodes . Map ( n => n != null ? n . Id : Guid . Empty ) ;
549+
550+ var maxDepth = subnodes . Max ( n => n != null ? n . MaxTreeDepth + 1 : 0 ) ;
551+ var minDepth = subnodes . Min ( n => n != null ? n . MinTreeDepth + 1 : 0 ) ;
552+
553+
554+ var octreeSplitLimit = splitLimit ;
555+ var fractions = LodExtensions . ComputeLodFractions ( subnodes ) ;
556+ var aggregateCount = Math . Min ( octreeSplitLimit , subnodes . Sum ( x => x ? . PointCountCell ) ?? 0 ) ;
557+ var counts = LodExtensions . ComputeLodCounts ( aggregateCount , fractions ) ;
558+
559+ // generate LoD data ...
560+ var needsCs = subnodes . Any ( x => x != null && x . HasColors ) ;
561+ var needsNs = subnodes . Any ( x => x != null && x . HasNormals ) ;
562+ var needsIs = subnodes . Any ( x => x != null && x . HasIntensities ) ;
563+ var needsKs = subnodes . Any ( x => x != null && x . HasClassifications ) ;
564+
565+ var subcenters = subnodes . Map ( x => x ? . Center ) ;
566+ var lodPs = LodExtensions . AggregateSubPositions ( counts , aggregateCount , root . Center , subcenters , subnodes . Map ( x => x ? . Positions ? . Value ) ) ;
567+ var lodCs = needsCs ? LodExtensions . AggregateSubArrays ( counts , aggregateCount , subnodes . Map ( x => x ? . Colors ? . Value ) ) : null ;
568+ var lodNs = needsNs ? LodExtensions . AggregateSubArrays ( counts , aggregateCount , subnodes . Map ( x => x ? . Normals ? . Value ) ) : null ;
569+ var lodIs = needsIs ? LodExtensions . AggregateSubArrays ( counts , aggregateCount , subnodes . Map ( x => x ? . Intensities ? . Value ) ) : null ;
570+ var lodKs = needsKs ? LodExtensions . AggregateSubArrays ( counts , aggregateCount , subnodes . Map ( x => x ? . Classifications ? . Value ) ) : null ;
571+ var lodKd = lodPs . Length < 1 ? null : lodPs . BuildKdTree ( ) ;
572+
573+
574+ Guid psId = Guid . NewGuid ( ) ;
575+ Guid kdId = lodKd != null ? Guid . NewGuid ( ) : Guid . Empty ;
576+ Guid csId = lodCs != null ? Guid . NewGuid ( ) : Guid . Empty ;
577+ Guid nsId = lodNs != null ? Guid . NewGuid ( ) : Guid . Empty ;
578+ Guid isId = lodIs != null ? Guid . NewGuid ( ) : Guid . Empty ;
579+ Guid ksId = lodKs != null ? Guid . NewGuid ( ) : Guid . Empty ;
580+
581+
582+ var newId = Guid . NewGuid ( ) ;
583+ storage . Add ( psId , lodPs ) ;
584+
585+ var bbloc = new Box3f ( lodPs ) ;
586+
587+ // be inner node
588+ var data = ImmutableDictionary < Durable . Def , object > . Empty
589+ . Add ( Durable . Octree . SubnodesGuids , subids )
590+ . Add ( Durable . Octree . NodeId , newId )
591+ . Add ( Durable . Octree . Cell , root . Cell )
592+ . Add ( Durable . Octree . BoundingBoxExactGlobal , bbabs )
593+ . Add ( Durable . Octree . BoundingBoxExactLocal , bbloc )
594+ . Add ( Durable . Octree . PositionsLocal3fReference , psId )
595+ . Add ( Durable . Octree . PointCountCell , lodPs . Length )
596+ . Add ( Durable . Octree . PointCountTreeLeafs , pointCountTree )
597+ . Add ( Durable . Octree . MaxTreeDepth , maxDepth )
598+ . Add ( Durable . Octree . MinTreeDepth , minDepth )
599+ ;
600+
601+
307602 if ( lodKd != null )
308603 {
309604 storage . Add ( kdId , lodKd . Data ) ;
0 commit comments