@@ -3239,6 +3239,130 @@ struct ST_Extent_Approx {
3239
3239
}
3240
3240
};
3241
3241
3242
+ // ======================================================================================================================
3243
+ // &&
3244
+ // ======================================================================================================================
3245
+
3246
+ struct Op_IntersectApprox {
3247
+
3248
+ // ------------------------------------------------------------------------------------------------------------------
3249
+ // Execute
3250
+ // ------------------------------------------------------------------------------------------------------------------
3251
+ static void Execute (DataChunk &args, ExpressionState &state, Vector &result) {
3252
+
3253
+ const auto count = args.size ();
3254
+ auto &box = args.data [0 ];
3255
+ auto &geom = args.data [1 ];
3256
+
3257
+ auto result_data = FlatVector::GetData<bool >(result);
3258
+
3259
+ // Convert box to unified format
3260
+ UnifiedVectorFormat box_vdata;
3261
+ box.ToUnifiedFormat (count, box_vdata);
3262
+
3263
+ // Get the struct entries and convert them to unified format
3264
+ const auto &bbox_vec = StructVector::GetEntries (box);
3265
+ UnifiedVectorFormat box_min_x_vdata, box_min_y_vdata, box_max_x_vdata, box_max_y_vdata;
3266
+ bbox_vec[0 ]->ToUnifiedFormat (count, box_min_x_vdata);
3267
+ bbox_vec[1 ]->ToUnifiedFormat (count, box_min_y_vdata);
3268
+ bbox_vec[2 ]->ToUnifiedFormat (count, box_max_x_vdata);
3269
+ bbox_vec[3 ]->ToUnifiedFormat (count, box_max_y_vdata);
3270
+
3271
+ const auto box_min_x_data = UnifiedVectorFormat::GetData<double >(box_min_x_vdata);
3272
+ const auto box_min_y_data = UnifiedVectorFormat::GetData<double >(box_min_y_vdata);
3273
+ const auto box_max_x_data = UnifiedVectorFormat::GetData<double >(box_max_x_vdata);
3274
+ const auto box_max_y_data = UnifiedVectorFormat::GetData<double >(box_max_y_vdata);
3275
+
3276
+ // Convert geometry to unified format
3277
+ UnifiedVectorFormat input_geom_vdata;
3278
+ geom.ToUnifiedFormat (count, input_geom_vdata);
3279
+ const auto input_geom = UnifiedVectorFormat::GetData<geometry_t >(input_geom_vdata);
3280
+
3281
+ for (idx_t i = 0 ; i < count; i++) {
3282
+ // Get the actual indices for box and geometry
3283
+ const auto box_idx = box_vdata.sel ->get_index (i);
3284
+ const auto geom_idx = input_geom_vdata.sel ->get_index (i);
3285
+
3286
+ // Check validity of both inputs
3287
+ if (!box_vdata.validity .RowIsValid (box_idx) || !input_geom_vdata.validity .RowIsValid (geom_idx)) {
3288
+ FlatVector::SetNull (result, i, true );
3289
+ continue ;
3290
+ }
3291
+
3292
+ // Get box coordinate indices
3293
+ const auto box_min_x_idx = box_min_x_vdata.sel ->get_index (i);
3294
+ const auto box_min_y_idx = box_min_y_vdata.sel ->get_index (i);
3295
+ const auto box_max_x_idx = box_max_x_vdata.sel ->get_index (i);
3296
+ const auto box_max_y_idx = box_max_y_vdata.sel ->get_index (i);
3297
+
3298
+ // Check validity of box coordinates
3299
+ if (!box_min_x_vdata.validity .RowIsValid (box_min_x_idx) ||
3300
+ !box_min_y_vdata.validity .RowIsValid (box_min_y_idx) ||
3301
+ !box_max_x_vdata.validity .RowIsValid (box_max_x_idx) ||
3302
+ !box_max_y_vdata.validity .RowIsValid (box_max_y_idx)) {
3303
+ FlatVector::SetNull (result, i, true );
3304
+ continue ;
3305
+ }
3306
+
3307
+ auto &geom_blob = input_geom[geom_idx];
3308
+
3309
+ // Try to get the cached bounding box from the blob
3310
+ Box2D<float > geom_bbox;
3311
+ if (geom_blob.TryGetCachedBounds (geom_bbox)) {
3312
+ const auto box_min_x = box_min_x_data[box_min_x_idx];
3313
+ const auto box_min_y = box_min_y_data[box_min_y_idx];
3314
+ const auto box_max_x = box_max_x_data[box_max_x_idx];
3315
+ const auto box_max_y = box_max_y_data[box_max_y_idx];
3316
+
3317
+ result_data[i] = (box_min_x <= geom_bbox.max .x && geom_bbox.min .x <= box_max_x) &&
3318
+ (box_min_y <= geom_bbox.max .y && geom_bbox.min .y <= box_max_y);
3319
+ } else {
3320
+ // No bounding box, return null
3321
+ FlatVector::SetNull (result, i, true );
3322
+ }
3323
+ }
3324
+
3325
+ if (box.GetVectorType () == VectorType::CONSTANT_VECTOR) {
3326
+ result.SetVectorType (VectorType::CONSTANT_VECTOR);
3327
+ }
3328
+ }
3329
+
3330
+ // ------------------------------------------------------------------------------------------------------------------
3331
+ // Register
3332
+ // ------------------------------------------------------------------------------------------------------------------
3333
+ static void Register (DatabaseInstance &db) {
3334
+ FunctionBuilder::RegisterScalar (db, " &&" , [](ScalarFunctionBuilder &func) {
3335
+ func.AddVariant ([](ScalarFunctionVariantBuilder &variant) {
3336
+ variant.AddParameter (" box" , GeoTypes::BOX_2D ());
3337
+ variant.AddParameter (" geom" , GeoTypes::GEOMETRY ());
3338
+ variant.SetReturnType (LogicalType::BOOLEAN);
3339
+
3340
+ variant.SetFunction (Execute);
3341
+ });
3342
+
3343
+ func.SetDescription (R"(
3344
+ Returns true if the bounding boxes intersects.
3345
+
3346
+ Note that, this operation is not very accurate; `&&` compares the cached bbox of the geometry using float precision.
3347
+ If you prefer accuracy, please use some other function like `ST_Intersects()`.
3348
+ )" );
3349
+
3350
+ func.SetExample (R"(
3351
+ SELECT ST_MakeBox2D('POINT (0 0)'::GEOMETRY, 'POINT (2 2)'::GEOMETRY) && ST_POINT(1, 1);
3352
+ ----
3353
+ true
3354
+
3355
+ SELECT ST_MakeBox2D('POINT (0 0)'::GEOMETRY, 'POINT (2 2)'::GEOMETRY) && ST_POINT(5, 5);
3356
+ ----
3357
+ false
3358
+ )" );
3359
+
3360
+ func.SetTag (" ext" , " spatial" );
3361
+ func.SetTag (" category" , " property" );
3362
+ });
3363
+ }
3364
+ };
3365
+
3242
3366
// ======================================================================================================================
3243
3367
// ST_ExteriorRing
3244
3368
// ======================================================================================================================
@@ -6516,6 +6640,105 @@ struct ST_MakePolygon {
6516
6640
}
6517
6641
};
6518
6642
6643
+ // ======================================================================================================================
6644
+ // ST_MakeBox2D
6645
+ // ======================================================================================================================
6646
+
6647
+ struct ST_MakeBox2D {
6648
+ // ------------------------------------------------------------------------------------------------------------------
6649
+ // Execute (GEOMETRY, GEOMETRY)
6650
+ // ------------------------------------------------------------------------------------------------------------------
6651
+ static void ExecuteBinary (DataChunk &args, ExpressionState &state, Vector &result) {
6652
+ auto &lstate = LocalState::ResetAndGet (state);
6653
+
6654
+ const auto &bbox_vec = StructVector::GetEntries (result);
6655
+ const auto min_x_data = FlatVector::GetData<double >(*bbox_vec[0 ]);
6656
+ const auto min_y_data = FlatVector::GetData<double >(*bbox_vec[1 ]);
6657
+ const auto max_x_data = FlatVector::GetData<double >(*bbox_vec[2 ]);
6658
+ const auto max_y_data = FlatVector::GetData<double >(*bbox_vec[3 ]);
6659
+
6660
+ UnifiedVectorFormat input_vdata1;
6661
+ UnifiedVectorFormat input_vdata2;
6662
+ args.data [0 ].ToUnifiedFormat (args.size (), input_vdata1);
6663
+ args.data [1 ].ToUnifiedFormat (args.size (), input_vdata2);
6664
+ const auto input_data1 = UnifiedVectorFormat::GetData<string_t >(input_vdata1);
6665
+ const auto input_data2 = UnifiedVectorFormat::GetData<string_t >(input_vdata2);
6666
+
6667
+ const auto count = args.size ();
6668
+
6669
+ for (idx_t out_idx = 0 ; out_idx < count; out_idx++) {
6670
+ const auto row_idx1 = input_vdata1.sel ->get_index (out_idx);
6671
+ const auto row_idx2 = input_vdata2.sel ->get_index (out_idx);
6672
+ if (!input_vdata1.validity .RowIsValid (row_idx1) || !input_vdata2.validity .RowIsValid (row_idx2)) {
6673
+ FlatVector::SetNull (result, out_idx, true );
6674
+ continue ;
6675
+ }
6676
+
6677
+ const auto &blob1 = input_data1[row_idx1];
6678
+ const auto &blob2 = input_data2[row_idx2];
6679
+ sgl::geometry geom1;
6680
+ sgl::geometry geom2;
6681
+ lstate.Deserialize (blob1, geom1);
6682
+ lstate.Deserialize (blob2, geom2);
6683
+
6684
+ if (geom1.get_type () != sgl::geometry_type::POINT || geom2.get_type () != sgl::geometry_type::POINT) {
6685
+ throw InvalidInputException (" ST_MakeBox2D only accepts POINT geometries" );
6686
+ }
6687
+
6688
+ if (geom1.is_empty () || geom2.is_empty ()) {
6689
+ FlatVector::SetNull (result, out_idx, true );
6690
+ continue ;
6691
+ }
6692
+
6693
+ const auto v1 = geom1.get_vertex_xy (0 );
6694
+ const auto v2 = geom2.get_vertex_xy (0 );
6695
+
6696
+ min_x_data[out_idx] = std::min (v1.x , v2.x );
6697
+ min_y_data[out_idx] = std::min (v1.y , v2.y );
6698
+ max_x_data[out_idx] = std::max (v1.x , v2.x );
6699
+ max_y_data[out_idx] = std::max (v1.y , v2.y );
6700
+ }
6701
+
6702
+ if (args.AllConstant ()) {
6703
+ result.SetVectorType (VectorType::CONSTANT_VECTOR);
6704
+ }
6705
+ }
6706
+
6707
+ // ------------------------------------------------------------------------------------------------------------------
6708
+ // Documentation
6709
+ // ------------------------------------------------------------------------------------------------------------------
6710
+ static constexpr auto DESCRIPTION_BINARY = R"(
6711
+ Create a BOX2D from two POINT geometries
6712
+ )" ;
6713
+ static constexpr auto EXAMPLE_BINARY = R"(
6714
+ SELECT ST_MakeBox2D(ST_Point(0, 0), ST_Point(1, 1));
6715
+ ----
6716
+ BOX(0 0, 1 1)
6717
+ )" ;
6718
+
6719
+ // ------------------------------------------------------------------------------------------------------------------
6720
+ // Register
6721
+ // ------------------------------------------------------------------------------------------------------------------
6722
+ static void Register (DatabaseInstance &db) {
6723
+ FunctionBuilder::RegisterScalar (db, " ST_MakeBox2D" , [](ScalarFunctionBuilder &func) {
6724
+ func.AddVariant ([](ScalarFunctionVariantBuilder &variant) {
6725
+ variant.AddParameter (" point1" , GeoTypes::GEOMETRY ());
6726
+ variant.AddParameter (" point2" , GeoTypes::GEOMETRY ());
6727
+ variant.SetReturnType (GeoTypes::BOX_2D ());
6728
+
6729
+ variant.SetInit (LocalState::Init);
6730
+ variant.SetFunction (ExecuteBinary);
6731
+
6732
+ variant.SetDescription (DESCRIPTION_BINARY);
6733
+ variant.SetExample (EXAMPLE_BINARY);
6734
+ });
6735
+
6736
+ func.SetTag (" ext" , " spatial" );
6737
+ func.SetTag (" category" , " construction" );
6738
+ });
6739
+ }
6740
+ };
6741
+
6519
6742
// ======================================================================================================================
6520
6743
// ST_Multi
6521
6744
// ======================================================================================================================
@@ -8609,6 +8832,7 @@ void RegisterSpatialScalarFunctions(DatabaseInstance &db) {
8609
8832
ST_EndPoint::Register (db);
8610
8833
ST_Extent::Register (db);
8611
8834
ST_Extent_Approx::Register (db);
8835
+ Op_IntersectApprox::Register (db);
8612
8836
ST_ExteriorRing::Register (db);
8613
8837
ST_FlipCoordinates::Register (db);
8614
8838
ST_Force2D::Register (db);
@@ -8636,6 +8860,7 @@ void RegisterSpatialScalarFunctions(DatabaseInstance &db) {
8636
8860
ST_MakeEnvelope::Register (db);
8637
8861
ST_MakeLine::Register (db);
8638
8862
ST_MakePolygon::Register (db);
8863
+ ST_MakeBox2D::Register (db);
8639
8864
ST_Multi::Register (db);
8640
8865
ST_NGeometries::Register (db);
8641
8866
ST_NInteriorRings::Register (db);
0 commit comments