Optimising latitude and longitude selection query
To find which vehicle(s) are in a specific 'rectangle' ("bounding box") during a particular day,

SELECT ...
    FROM gdata
    WHERE gDateTime &gt;= '2017-07-03'
      AND gDateTime  &lt; '2017-07-03' + INTERVAL 1 DAY
      AND latitude &gt; 34.567
      AND latitude &lt; 35.678
      AND longitude &gt; 123.456
      AND longitude &lt; 124.567;


The optimizer cannot do a perfect job of optimizing the query, but you can give it 3 choices and hope that it picks the best:

INDEX(gDateTime),
INDEX(latitude),
INDEX(longitude)


Since each column is used in a "range", there is no advantage in putting two columns in a single index.  (Only the first column will be used.)

Or, with SPATIAL index...

If it is a polygon, not a simple rectangle, then something like

SELECT ...
    FROM gdata
    WHERE gDateTime &gt;= '2017-07-03'
      AND gDateTime  &lt; '2017-07-03' + INTERVAL 1 DAY
      AND MBRWithin(pt, ...);


with


pt being an extra column containing a POINT
SPATIAL(pt)
the '...' being a pre-calculated polygon from somewhere else


Do not call your FUNCTION in the WHERE clause; that will be terribly inefficient.

Since you only want a list of vehicleID, not all the locations, this is probably better:

SELECT DISTINCT vehicleID
    FROM gdata
    WHERE ...


DISTINCT is sort of a degenerate case of GROUP BY.  I prefer to use DISTINCT in this situation since it makes it clearer what is going on.

Partitioning?

PARTITION BY RANGE(TO_DAYS(gDateTime)) with 20-50 partitions may help performance, especially if the table will be billions of rows long.  The partitioning would narrow the focus to one (maybe more) partition, then do the spatial (or lat/lng) lookup within just that partition.

Also, partitioning is an excellent way to purge 'old' data.

Use cases 1 and 2 of my partition blog discuss those two ideas.