mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
6ba46ffa90
* Maptools cleanup * Changed conditions to check * Minor cleanup + fix
220 lines
7.4 KiB
Plaintext
220 lines
7.4 KiB
Plaintext
#include "..\script_component.hpp"
|
|
/*
|
|
* Author: LorenLuke, johnb43
|
|
* Handle map marker creation.
|
|
* If a marker is (partially) on the plotting board, the parts on the plotting board are attached to the plotting board
|
|
* and move with the board accordingly.
|
|
*
|
|
* Arguments:
|
|
* 0: Arguments <ARRAY>
|
|
* - 0: Marker name <STRING>
|
|
* - 1: Chat channel number <NUMBER>
|
|
* - 2: Marker owner <OBJECT>
|
|
* - 3: Local origin <BOOL>
|
|
* 1: Deleted <BOOL>
|
|
*
|
|
* Return Value:
|
|
* None
|
|
*
|
|
* Example:
|
|
* [CONTROL, [0, 5]] call ace_maptools_fnc_handlePlottingBoardMarkers
|
|
*
|
|
* Public: No
|
|
*/
|
|
|
|
params ["_args", "_deleted"];
|
|
_args params ["_marker", "_channelNumber", "_owner", "_local"];
|
|
|
|
if (_deleted) exitWith {
|
|
GVAR(plottingBoard_markers) deleteAt _marker;
|
|
};
|
|
|
|
// Do not process non-local or already processed markers, don't check if the plotting board isn't shown
|
|
if (!_local || {GVAR(plottingBoard_Shown) == 0} || {QUOTE(ADDON) in _marker}) exitWith {};
|
|
|
|
// Check if the channel the marker was made in can be marked on the plotting board
|
|
private _continue = true;
|
|
|
|
if (isMultiplayer) then {
|
|
switch (GVAR(plottingBoardAllowChannelDrawing)) do {
|
|
case 0: {
|
|
if (_channelNumber != 5) then {_continue = false};
|
|
};
|
|
case 1: {
|
|
if !(_channelNumber in [3, 5]) then {_continue = false};
|
|
};
|
|
};
|
|
};
|
|
|
|
if (!_continue) exitWith {};
|
|
|
|
private _boardPos = GVAR(plottingBoard_pos);
|
|
private _boardAng = GVAR(plottingBoard_acrylicAngle);
|
|
|
|
private _markerPolyline = markerPolyline _marker;
|
|
private _count = count _markerPolyline;
|
|
|
|
// If the marker is not a polyline marker
|
|
if (_count == 0) exitWith {
|
|
private _diffPos = (getMarkerPos _marker) vectorDiff _boardPos;
|
|
|
|
// If the marker is on the acrylic or ruler of the plotting board, save it
|
|
if (vectorMagnitude _diffPos < PLOTTINGBOARD_DRAWRANGE) then {
|
|
private _relPos = [[0, 0], _diffPos, _boardAng] call CBA_fnc_vectRotate2D;
|
|
|
|
GVAR(plottingBoard_markers) set [_marker, [_relPos, [], _boardAng, +_boardPos, 1]];
|
|
};
|
|
};
|
|
|
|
// If the marker is a polyline marker, but doesn't have enough components (happens when you ctrl-left click on the map), ignore
|
|
if (_count <= 4) exitWith {};
|
|
|
|
// Polyine markers (lines)
|
|
private _startPos = [];
|
|
private _endPos = [];
|
|
private _dir = [];
|
|
private _diffPos = [];
|
|
|
|
private _a = 0;
|
|
private _b = 0;
|
|
private _c = 0;
|
|
private _t1 = nil;
|
|
private _t2 = nil;
|
|
private _delta = 0;
|
|
|
|
private _intersectionValid1 = false;
|
|
private _intersectionValid2 = false;
|
|
private _intersectPoint1 = [];
|
|
private _intersectPoint2 = [];
|
|
private _intersectClose = [];
|
|
private _intersectFar = [];
|
|
|
|
private _polylineIndex = 0;
|
|
private _markerArray = [[]];
|
|
private _insideArray = [];
|
|
|
|
for "_i" from 0 to _count - 1 - 2 step 2 do {
|
|
_startPos = [_markerPolyline select _i, _markerPolyline select (_i + 1)];
|
|
_endPos = [_markerPolyline select (_i + 2), _markerPolyline select (_i + 3)];
|
|
_dir = _endPos vectorDiff _startPos;
|
|
_diffPos = _startPos vectorDiff _boardPos;
|
|
|
|
// Circle-line intersection: Check for intersections between plotting board and current piece of polyline
|
|
// https://stackoverflow.com/a/1084899
|
|
_a = _dir vectorDotProduct _dir;
|
|
_b = 2 * (_diffPos vectorDotProduct _dir);
|
|
_c = (_diffPos vectorDotProduct _diffPos) - PLOTTINGBOARD_DRAWRANGE^2;
|
|
|
|
_delta = _b^2 - 4 * _a * _c;
|
|
|
|
// Stretch factors
|
|
_t1 = nil;
|
|
_t2 = nil;
|
|
|
|
if (_delta > 0) then {
|
|
_t1 = (-_b + sqrt _delta) / (2 * _a);
|
|
_t2 = (-_b - sqrt _delta) / (2 * _a);
|
|
|
|
// Don't look for intersection points beyond the start or end points
|
|
if (_t1 < 0 || _t1 > 1) then {
|
|
_t1 = nil;
|
|
};
|
|
|
|
if (_t2 < 0 || _t2 > 1) then {
|
|
_t2 = nil;
|
|
};
|
|
};
|
|
|
|
// The current point is always part of a polyline
|
|
(_markerArray param [_polylineIndex, []]) append _startPos;
|
|
_insideArray set [_polylineIndex, vectorMagnitude _diffPos < PLOTTINGBOARD_DRAWRANGE]; // keep track if point is within plotting board
|
|
|
|
_intersectionValid1 = !isNil "_t1";
|
|
_intersectionValid2 = !isNil "_t2";
|
|
|
|
// If no valid intersection points, continue
|
|
if (!_intersectionValid1 && {!_intersectionValid2}) then {
|
|
continue;
|
|
};
|
|
|
|
// Extremely rare case if the marker is tangential to the plotting board: Ignore
|
|
if (_intersectionValid1 && {_intersectionValid2} && {_t1 == _t2}) then {
|
|
continue;
|
|
};
|
|
|
|
if (_intersectionValid1) then {
|
|
_intersectPoint1 = _startPos vectorAdd (_dir vectorMultiply _t1);
|
|
};
|
|
|
|
if (_intersectionValid2) then {
|
|
_intersectPoint2 = _startPos vectorAdd (_dir vectorMultiply _t2);
|
|
};
|
|
|
|
// When a marker crosses the plotting board entirely (one straight line through the plotting board)
|
|
if (_intersectionValid1 && {_intersectionValid2}) then {
|
|
// Take the closer point first
|
|
_intersectClose = [_intersectPoint1, _intersectPoint2] select (_t1 > _t2);
|
|
|
|
// Finish previous polyline with the last point being the intersection
|
|
(_markerArray select _polylineIndex) append _intersectClose;
|
|
|
|
// Create a new polyline, with the first point being the closest intersection
|
|
_polylineIndex = _polylineIndex + 1;
|
|
_markerArray set [_polylineIndex, _intersectClose];
|
|
|
|
// Now take the point further away
|
|
_intersectFar = [_intersectPoint1, _intersectPoint2] select (_t1 < _t2);
|
|
|
|
// Make a polyline between the intersection points
|
|
(_markerArray select _polylineIndex) append _intersectClose;
|
|
(_markerArray select _polylineIndex) append _intersectFar;
|
|
_insideArray set [_polylineIndex, true]; // with 2 intersections, this part of the polyline must be inside
|
|
|
|
// Create a new polyline, with the first point being the furthest intersection
|
|
_polylineIndex = _polylineIndex + 1;
|
|
_markerArray set [_polylineIndex, _intersectFar];
|
|
} else {
|
|
// Only 1 intersection (either point 1 or 2, exclusive or)
|
|
if (_intersectionValid2) then {
|
|
_intersectPoint1 = _intersectPoint2;
|
|
};
|
|
|
|
// Finish previous polyline with the last point being the intersection
|
|
(_markerArray select _polylineIndex) append _intersectPoint1;
|
|
|
|
// Create a new polyline, with the first point being the intersection
|
|
_polylineIndex = _polylineIndex + 1;
|
|
_markerArray set [_polylineIndex, _intersectPoint1];
|
|
};
|
|
};
|
|
|
|
// If there were no polyline intersections and the marker was not on the plotting board, don't create new markers
|
|
if (_insideArray isEqualTo [false]) exitWith {};
|
|
|
|
private _color = getMarkerColor _marker;
|
|
private _name = "";
|
|
private _polylineRelative = [];
|
|
private _relPos = [];
|
|
|
|
{
|
|
_name = format ["%1-%2-%3", _marker, _forEachIndex, QUOTE(ADDON)]; // adding an identifier allow to check if marker was already processed
|
|
createMarkerLocal [_name, [0, 0], _channelNumber, _owner];
|
|
_name setMarkerColorLocal _color;
|
|
_name setMarkerPolyline _x; // global marker broadcast
|
|
|
|
// If the marker was on the plotting board, take it's unrotated position and store it
|
|
if (_insideArray select _forEachIndex) then {
|
|
_polylineRelative = [];
|
|
|
|
for "_i" from 0 to count _x - 1 step 2 do {
|
|
_relPos = [[0, 0], [_x select _i, _x select (_i + 1)] vectorDiff _boardPos, _boardAng] call CBA_fnc_vectRotate2D;
|
|
_polylineRelative append _relPos;
|
|
};
|
|
|
|
GVAR(plottingBoard_markers) set [_name, [[0, 0], +_polylineRelative, _boardAng, +_boardPos, 1]];
|
|
};
|
|
} forEach _markerArray;
|
|
|
|
// Delete original marker
|
|
deleteMarker _marker;
|