@@ -37,6 +37,14 @@ void RadiusAssignFilter::addArgs(ProgramArgs& args)
3737 args.add (" update_expression" , " Value to assign to dimension of points of src_domain "
3838 " that have at least one neighbor in reference domain based on expression." ,
3939 m_updateExpr);
40+ args.add (" is3d" , " Search in 3d" , m_search3d, false );
41+ args.add (" max2d_above" , " if search in 2d : upward maximum distance in Z for potential neighbors "
42+ " (corresponds to a search in a cylinder with a height = max2d_above above the source point). "
43+ " Values < 0 mean infinite height" , m_max2dAbove, -1 .);
44+ args.add (" max2d_below" , " if search in 2d : downward maximum distance in Z for potential neighbors ("
45+ " corresponds to a search in a cylinder with a height = max2d_below below the source point). "
46+ " Values < 0 mean infinite height" , m_max2dBelow, -1 .);
47+
4048}
4149
4250
@@ -104,27 +112,49 @@ void RadiusAssignFilter::ready(PointTableRef)
104112}
105113
106114
107- void RadiusAssignFilter::doOneNoDomain (PointRef &point, KD2Index &kdi )
115+ void RadiusAssignFilter::doOneNoDomain (PointRef &pointSrc )
108116{
109- PointIdList iNeighbors = kdi.radius (point, m_radius);
117+ PointIdList iNeighbors;
118+ if (m_search3d) iNeighbors = refView->build3dIndex ().radius (pointSrc, m_radius);
119+ else iNeighbors = refView->build2dIndex ().radius (pointSrc, m_radius);
120+
121+
110122 if (iNeighbors.size () == 0 )
111123 return ;
112124
113- m_ptsToUpdate.push_back (point.pointId ());
125+ if (!m_search3d && (m_max2dBelow>=0 || m_max2dAbove>=0 ))
126+ {
127+ double Zsrc = pointSrc.getFieldAs <double >(Dimension::Id::Z);
128+
129+ bool take (false );
130+ for (PointId ptId : iNeighbors)
131+ {
132+ double Zref = refView->point (ptId).getFieldAs <double >(Dimension::Id::Z);
133+ if (m_max2dAbove>=0 && Zref>Zsrc && (Zref-Zsrc)>m_max2dAbove) continue ;
134+ if (m_max2dBelow>=0 && Zsrc>Zref && (Zsrc-Zref)>m_max2dBelow) continue ;
135+ take = true ;
136+ break ;
137+ }
138+
139+ if (!take) return ;
140+ }
141+
142+
143+ m_ptsToUpdate.push_back (pointSrc.pointId ());
114144
115145}
116146
117147// update point. kdi and temp both reference the NN point cloud
118- bool RadiusAssignFilter::doOne (PointRef& point, KD2Index &kdi )
148+ bool RadiusAssignFilter::doOne (PointRef& pointSrc )
119149{
120150 if (m_srcDomain.empty ()) // No domain, process all points
121- doOneNoDomain (point, kdi );
151+ doOneNoDomain (pointSrc );
122152
123153 for (DimRange& r : m_srcDomain)
124154 { // process only points that satisfy a domain condition
125- if (r.valuePasses (point .getFieldAs <double >(r.m_id )))
155+ if (r.valuePasses (pointSrc .getFieldAs <double >(r.m_id )))
126156 {
127- doOneNoDomain (point, kdi );
157+ doOneNoDomain (pointSrc );
128158 break ;
129159 }
130160 }
@@ -133,22 +163,21 @@ bool RadiusAssignFilter::doOne(PointRef& point, KD2Index &kdi)
133163
134164void RadiusAssignFilter::filter (PointView& view)
135165{
136- PointRef point_src (view, 0 );
137- // Create a kd tree only with the points in the reference domain (to make the search faster)
138- PointViewPtr refView;
139- PointRef temp (view, 0 );
166+ PointRef pointTemp (view, 0 );
167+
168+ // Create reference domain view
169+ refView = view. makeNew ( );
140170 if (m_referenceDomain.empty ())
141171 for (PointId id = 0 ; id < view.size (); ++id)
142172 refView->appendPoint (view, id);
143173 else
144174 {
145- refView = view.makeNew ();
146175 for (PointId id = 0 ; id < view.size (); ++id)
147176 {
148177 for (DimRange& r : m_referenceDomain)
149- { // process only points that satisfy a domain condition
150- temp .setPointId (id);
151- if (r.valuePasses (temp .getFieldAs <double >(r.m_id )))
178+ {
179+ pointTemp .setPointId (id);
180+ if (r.valuePasses (pointTemp .getFieldAs <double >(r.m_id )))
152181 {
153182 refView->appendPoint (view, id);
154183 break ;
@@ -157,20 +186,23 @@ void RadiusAssignFilter::filter(PointView& view)
157186 }
158187 }
159188
160- KD2Index& kdiRef = refView-> build2dIndex ();
189+ // Process all points (mark them if they need to be updated)
161190 for (PointId id = 0 ; id < view.size (); ++id)
162191 {
163- point_src .setPointId (id);
164- doOne (point_src, kdiRef );
192+ pointTemp .setPointId (id);
193+ doOne (pointTemp );
165194 }
195+
196+
166197 for (auto id: m_ptsToUpdate)
167198 {
168- temp .setPointId (id);
199+ pointTemp .setPointId (id);
169200 for (expr::AssignStatement& expr : m_updateExpr)
170- // if (expr.conditionalExpr().eval(temp ))
171- temp .setField (expr.identExpr ().eval (), expr.valueExpr ().eval (temp ));
201+ if (expr.conditionalExpr ().eval (pointTemp ))
202+ pointTemp .setField (expr.identExpr ().eval (), expr.valueExpr ().eval (pointTemp ));
172203 }
173204}
174205
206+
175207} // namespace pdal
176208
0 commit comments