#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 * - 0: Marker name * - 1: Chat channel number * - 2: Marker owner * - 3: Local origin * 1: Deleted * * 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;