---
name: "lineIntersectsSurfaces"
type: command
status: ok
groups: ["Math - Geometry"]
arma3_since: "1.50"
locality: {"argument": "global", "effect": null, "server_exec": false}
source: https://community.bistudio.com/wiki/lineIntersectsSurfaces
revid: 377700
updated: 2026-01-02T09:03:29Z
---

# lineIntersectsSurfaces

*Command · Math - Geometry · Arma 3 v1.50*

Locality: arguments **global**

## Description

Returns a list of intersections with surfaces and ground from *begPosASL* to *endPosASL*. Doesn't return intersection with sea surface. Works underwater, unlike [lineIntersects](../commands/lineIntersects.md). Hardcoded max distance: 5000m.

> [!IMPORTANT]
> - if *begPosASL* is under the ground and *endPosASL* is above it, the command will only return intersection with the ground, this is an engine limitation and none of the intersectXXX commands will work when initiated from under the ground.
> - only a single LOD is checked for intersection. LOD2 will only be checked if LOD1 is unavailable.

Since Arma 3 v2.20, there is an alternative syntax that does multiple checks in parallel, faster than multiple calls.

## Syntax

### Syntax 1

```sqf
lineIntersectsSurfaces [begPosASL, endPosASL, ignoreObj1, ignoreObj2, sortMode, maxResults, LOD1, LOD2, returnUnique]
```

**Parameters:**

- `begPosASL`: [PositionASL](../topics/Position.md#positionasl) - virtual line start
- `endPosASL`: [PositionASL](../topics/Position.md#positionasl) - virtual line end
- `ignoreObj1`: [Object](../topics/Object.md) - (Optional, default [objNull](../commands/objNull.md)) first object to ignore
- `ignoreObj2`: [Object](../topics/Object.md) - (Optional, default [objNull](../commands/objNull.md)) second object to ignore
- `sortMode`: [Boolean](../topics/Boolean.md) -  (Optional, default [true](../commands/true.md)) [true](../commands/true.md): closest to furthest, [false](../commands/false.md): furthest to closest
- `maxResults`: [Number](../topics/Number.md) - (Optional, default 1) max results to return. -1 to return every result
- `LOD1`: [String](../topics/String.md) - (Optional, default "VIEW") primary LOD to look for intersection. Can be one of:
  - "FIRE"
  - "VIEW"
  - "GEOM"
  - "IFIRE" - ("I" stands for Indirect, *almost* identical to "FIRE")
  - "NONE"
  - Arma 3 v2.02 "PHYSX" - PhysX geometry LOD
  - Arma 3 v2.08 "ROADWAY" - only works from the top *(since arma3 1.52)*
- `LOD2`: [String](../topics/String.md) - (Optional, default "FIRE") secondary LOD to look for intersection. See *LOD1* for possible values *(since arma3 1.52)*
- `returnUnique`: [Boolean](../topics/Boolean.md) - (Optional, default [true](../commands/true.md)) when [false](../commands/false.md), all intersections in the same object are included, otherwise only the first one *(since arma3 1.70)*

**Returns:** [Array](../topics/Array.md) of [Array](../topics/Array.md)s with [intersectPosASL, surfaceNormal, intersectObj, parentObject, selectionNames, pathToBisurf]
- intersectPosASL: [PositionASL](../topics/Position.md) - the actual position where line intersects surface
- [surfaceNormal](../commands/surfaceNormal.md): [Vector](../topics/Vector3D.md) - a normal to the intersected surface
- intersectObject: [Object](../topics/Object.md) - the object the surface belongs to (could be proxy object) - [objNull](../commands/objNull.md) if terrain
- parentObject: [Object](../topics/Object.md) - the object proxy object belongs to (not always the same as intersect object) - [objNull](../commands/objNull.md) if terrain
- Arma 3 v2.10 [selectionNames](../commands/selectionNames.md): [Array](../topics/Array.md) of [String](../topics/String.md)s - Names of the intersected selections (bones). Returns `[]` if there is no intersection with a selection.
- Arma 3 v2.10 pathToBisurf: [String](../topics/String.md) - path to intersected surface properties (.bisurf) file. Returns `""` if surface has no special properties. Terrain surface properties begin with `1.`, and the surface properties are defined in `CfgSurfaces`. For example, if it returns `1. GdtVRsurface01`, properties are defined in: `configFile >> "CfgSurfaces" >> "GdtVRsurface01"`

### Syntax 2

*since arma3 2.20*

```sqf
lineIntersectsSurfaces [[element1, element2, ...]]
```

**Parameters:**

- `elementN`: [Array](../topics/Array.md) with [begPosASL, endPosASL, ignoreObj1, ignoreObj2, sortMode, maxResults, LOD1, LOD2, returnUnique]
  - begPosASL: [PositionASL](../topics/Position.md#positionasl) - virtual line start
  - endPosASL: [PositionASL](../topics/Position.md#positionasl) - virtual line end
  - ignoreObj1: [Object](../topics/Object.md) - (Optional, default [objNull](../commands/objNull.md)) first object to ignore
  - ignoreObj2: [Object](../topics/Object.md) - (Optional, default [objNull](../commands/objNull.md)) second object to ignore
  - sortMode: [Boolean](../topics/Boolean.md) -  (Optional, default [true](../commands/true.md)) [true](../commands/true.md): closest to furthest, [false](../commands/false.md): furthest to closest
  - maxResults: [Number](../topics/Number.md) - (Optional, default 1) max results to return. -1 to return every result
  - LOD1: [String](../topics/String.md) - (Optional, default "VIEW") primary LOD to look for intersection. Can be one of:
    - "FIRE"
    - "VIEW"
    - "GEOM"
    - "IFIRE" - ("I" stands for Indirect, *almost* identical to "FIRE")
    - "NONE"
    - "PHYSX" - PhysX geometry LOD
    - "ROADWAY" - only works from the top
  - LOD2: [String](../topics/String.md) - (Optional, default "FIRE") secondary LOD to look for intersection. See *LOD1* for possible values
  - returnUnique: [Boolean](../topics/Boolean.md) - (Optional, default [true](../commands/true.md)) when [false](../commands/false.md), all intersections in the same object are included, otherwise only the first one

**Returns:** [Array](../topics/Array.md) of [Array](../topics/Array.md)s with [intersectPosASL, surfaceNormal, intersectObj, parentObject, selectionNames, pathToBisurf]
- intersectPosASL: [PositionASL](../topics/Position.md) - the actual position where line intersects surface
- [surfaceNormal](../commands/surfaceNormal.md): [Vector](../topics/Vector3D.md) - a normal to the intersected surface
- intersectObject: [Object](../topics/Object.md) - the object the surface belongs to (could be proxy object) - [objNull](../commands/objNull.md) if terrain
- parentObject: [Object](../topics/Object.md) - the object proxy object belongs to (not always the same as intersect object) - [objNull](../commands/objNull.md) if terrain
- [selectionNames](../commands/selectionNames.md): [Array](../topics/Array.md) of [String](../topics/String.md)s - Names of the intersected selections (bones). Returns `[]` if there is no intersection with a selection.
- pathToBisurf: [String](../topics/String.md) - path to intersected surface properties (.bisurf) file. Returns `""` if surface has no special properties. Terrain surface properties begin with `1.`, and the surface properties are defined in `CfgSurfaces`. For example, if it returns `1. GdtVRsurface01`, properties are defined in: `configFile >> "CfgSurfaces" >> "GdtVRsurface01"`

## Examples

### Example 1

```sqf
_intersections = lineIntersectsSurfaces [eyePos player, aimPos chopper, player, chopper, true, -1];
```

### Example 2

```sqf
arrow = "Sign_Arrow_F" createVehicle [0,0,0];
onEachFrame {
    _ins = lineIntersectsSurfaces [
        AGLToASL positionCameraToWorld [0,0,0], 
        AGLToASL positionCameraToWorld [0,0,1000], 
        player
    ];
    if (count _ins == 0) exitWith { arrow setPosASL [0,0,0] };
    arrow setPosASL (_ins select 0 select 0);
    arrow setVectorUp (_ins select 0 select 1);
    hintSilent str _ins;
};
```

### Example 3

This should detect glass windows and wire fences (since Arma 3 v1.52):

```sqf
wirefence = "Land_New_WiredFence_5m_F" createVehicle position player;
arrow = "Sign_Arrow_F" createVehicle [0,0,0];
onEachFrame {
    _ins = lineIntersectsSurfaces [
        AGLToASL positionCameraToWorld [0,0,0], 
        AGLToASL positionCameraToWorld [0,0,1000], 
        player,
        objNull,
        true,
        1,
        "GEOM",
        "NONE"
    ];
    if (count _ins == 0) exitWith { arrow setPosASL [0,0,0] };
    arrow setPosASL (_ins select 0 select 0);
    arrow setVectorUp (_ins select 0 select 1);
    hintSilent str _ins;
};
```

### Example 4

Alternative syntax to check intersections in parallel. Will draw a redline to the first intersecting object between the player and unit:

```sqf
private _handle = addMissionEventHandler ["Draw3D", {
    private _enemies = units opfor;
    private _enemyDataArray = _enemies apply { [eyePos player, eyePos _x, player, _x] };
    
    private _intersections = lineIntersectsSurfaces [_enemyDataArray];
    {
        // No intersections found, draw green '+' icon at unit
        if (_x isEqualTo []) then {
            drawIcon3D [
                "\a3\ui_f\data\gui\cfg\cursors\add_gs.paa",
                [0, 1, 0, 1],
                ASLToAGL (eyePos (_enemies#_forEachIndex)),
                0.5, 0.5, 0,
                str (_enemies#_forEachIndex)
            ];
        } else {
            private _firstIntersection = _x#0;
            // Draw red line and '+' icon to first intersecting object
            drawIcon3D [
                "\a3\ui_f\data\gui\cfg\cursors\add_gs.paa",
                [1, 0, 0, 1],
                ASLToAGL (_firstIntersection#0),
                0.5, 0.5, 0,
                str (_enemies#_forEachIndex) + "- Blocked by " + str (_firstIntersection#2)
            ];
            drawLine3D [
                ASLToAGL (eyePos player),
                ASLToAGL (_firstIntersection#0),
                [1, 0, 0, 1],
                5
            ];
        };
    } forEach _intersections;
}];
```

## See also

[lineIntersectsObjs](../commands/lineIntersectsObjs.md) · [lineIntersectsWith](../commands/lineIntersectsWith.md) · [lineIntersects](../commands/lineIntersects.md) · [terrainIntersectASL](../commands/terrainIntersectASL.md) · [terrainIntersectAtASL](../commands/terrainIntersectAtASL.md) · [terrainIntersect](../commands/terrainIntersect.md) · [intersect](../commands/intersect.md) · [cursorObject](../commands/cursorObject.md) · [cursorTarget](../commands/cursorTarget.md) · [checkVisibility](../commands/checkVisibility.md)

## Community notes

**Killzone_Kid** — 2015-08-27

Fast check if the player is in a house:

```sqf
KK_fnc_inHouse = {
    lineIntersectsSurfaces [
        getPosWorld _this, 
        getPosWorld _this vectorAdd [0, 0, 50], 
        _this, objNull, true, 1, "GEOM", "NONE"
    ] select 0 params ["","","","_house"];
    if (_house isKindOf "House") exitWith { true };
    false
};
onEachFrame { hintSilent str (player call KK_fnc_inHouse) };
```

---

**Pierre MGI** — 2016-01-30

This command is useful to place weaponholder (and then spawned weapons) on floor of houses, correcting  the spawn position (can_collide) to intersect with floor:

```sqf
MGI_fnc_setPosAGLS = {
    params ["_obj", "_pos"];
    _wh_pos = getPosASL _obj;

    _pos set [2, (ATLToASL _pos select 2) - 10];
    _ins = lineIntersectsSurfaces [_wh_pos, _pos,_obj, objNull, true, 1, "VIEW", "FIRE"];
    _surface_distance = if (count _ins > 0) then [{ (_ins select 0 select 0) distance _wh_pos }, { 0 }];
    _wh_pos set [2, (getPosASL _obj select 2) - (_surface_distance)];
    _weaponholder setPosASL _wh_pos;
};
```

After the position (_pos) obtained in BIS_fnc_buidingPositions array:

```sqf
private _weaponHolder = createVehicle ["groundWeaponHolder", _pos, [], 0, "CAN_COLLIDE"];
[_weaponHolder, _pos] call MGI_fnc_setPosAGLS;
```

Then fill your weapon holder.

---

**Tankbuster** — 2024-01-06

Note that dome_big and dome_small objects have glass roof panels which this function can't see if it intersects those windows

<sub>Source: [BI Community Wiki — lineIntersectsSurfaces](https://community.bistudio.com/wiki/lineIntersectsSurfaces) (revision 377700).</sub>
