diff --git a/.idea/.idea.hse-ar-scanner/.idea/indexLayout.xml b/.idea/.idea.hse-ar-scanner/.idea/indexLayout.xml
index 4ab2dbead55c0f061d587baee8d0da1cfb2173fb..31fefb2377ad9093fd1d9c0cf8e93c0321883312 100644
--- a/.idea/.idea.hse-ar-scanner/.idea/indexLayout.xml
+++ b/.idea/.idea.hse-ar-scanner/.idea/indexLayout.xml
@@ -1,31 +1,31 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ContentModelUserStore">
-    <attachedFolders />
-    <explicitIncludes>
-      <Path>Library/PackageCache/com.unity.collab-proxy@1.2.16</Path>
-      <Path>Library/PackageCache/com.unity.ext.nunit@1.0.6</Path>
-      <Path>Library/PackageCache/com.unity.ide.rider@1.1.4</Path>
-      <Path>Library/PackageCache/com.unity.ide.vscode@1.2.3</Path>
-      <Path>Library/PackageCache/com.unity.multiplayer-hlapi@1.0.8</Path>
-      <Path>Library/PackageCache/com.unity.subsystemregistration@1.0.6</Path>
-      <Path>Library/PackageCache/com.unity.test-framework@1.1.22</Path>
-      <Path>Library/PackageCache/com.unity.textmeshpro@2.0.1</Path>
-      <Path>Library/PackageCache/com.unity.timeline@1.2.18</Path>
-      <Path>Library/PackageCache/com.unity.xr.legacyinputhelpers@2.1.7</Path>
-      <Path>Library/PackageCache/com.unity.xr.management@3.2.17</Path>
-      <Path>Library/PackageCache/nuget.mono-cecil@0.1.6-preview</Path>
-      <Path>Packages</Path>
-      <Path>ProjectSettings</Path>
-    </explicitIncludes>
-    <explicitExcludes>
-      <Path>.git</Path>
-      <Path>.idea</Path>
-      <Path>Builds</Path>
-      <Path>Library</Path>
-      <Path>Logs</Path>
-      <Path>Temp</Path>
-      <Path>obj</Path>
-    </explicitExcludes>
-  </component>
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ContentModelUserStore">
+    <attachedFolders />
+    <explicitIncludes>
+      <Path>Library/PackageCache/com.unity.collab-proxy@1.2.16</Path>
+      <Path>Library/PackageCache/com.unity.ext.nunit@1.0.6</Path>
+      <Path>Library/PackageCache/com.unity.ide.rider@1.1.4</Path>
+      <Path>Library/PackageCache/com.unity.ide.vscode@1.2.3</Path>
+      <Path>Library/PackageCache/com.unity.multiplayer-hlapi@1.0.8</Path>
+      <Path>Library/PackageCache/com.unity.subsystemregistration@1.0.6</Path>
+      <Path>Library/PackageCache/com.unity.test-framework@1.1.22</Path>
+      <Path>Library/PackageCache/com.unity.textmeshpro@2.0.1</Path>
+      <Path>Library/PackageCache/com.unity.timeline@1.2.18</Path>
+      <Path>Library/PackageCache/com.unity.xr.legacyinputhelpers@2.1.7</Path>
+      <Path>Library/PackageCache/com.unity.xr.management@3.2.17</Path>
+      <Path>Library/PackageCache/nuget.mono-cecil@0.1.6-preview</Path>
+      <Path>Packages</Path>
+      <Path>ProjectSettings</Path>
+    </explicitIncludes>
+    <explicitExcludes>
+      <Path>.git</Path>
+      <Path>.idea</Path>
+      <Path>Builds</Path>
+      <Path>Library</Path>
+      <Path>Logs</Path>
+      <Path>Temp</Path>
+      <Path>obj</Path>
+    </explicitExcludes>
+  </component>
 </project>
\ No newline at end of file
diff --git a/Assets/FpsCounter.cs b/Assets/FpsCounter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1eb1f7f835d3b970c12131c7ab451b11bf32e22b
--- /dev/null
+++ b/Assets/FpsCounter.cs
@@ -0,0 +1,30 @@
+п»їusing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class FpsCounter : MonoBehaviour
+{
+    float deltaTime = 0.0f;
+ 
+    void Update()
+    {
+        deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
+    }
+ 
+    void OnGUI()
+    {
+        int w = Screen.width, h = Screen.height;
+ 
+        GUIStyle style = new GUIStyle();
+ 
+        Rect rect = new Rect(0, 0, w, h * 2 / 100);
+        style.alignment = TextAnchor.UpperLeft;
+        style.fontSize = h * 2 / 100;
+        style.normal.textColor = new Color (0.0f, 0.0f, 0.5f, 1.0f);
+        float msec = deltaTime * 1000.0f;
+        float fps = 1.0f / deltaTime;
+        string text = string.Format("{0:0.0} ms ({1:0.} fps)", msec, fps);
+        GUI.Label(rect, text, style);
+    }
+}
\ No newline at end of file
diff --git a/Assets/FpsCounter.cs.meta b/Assets/FpsCounter.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..1eaabefb694f2ffa28ff11fbcda983aac184ebde
--- /dev/null
+++ b/Assets/FpsCounter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 905a87ab2b3c59f4abeebb4b006fe010
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Resources/Materials/Pc.mat b/Assets/Resources/Materials/Pc.mat
index e1f848ea5c05e7b25067bf2238e01eccf94f0a67..bc997af5a69fec5caece0b97b0ef827f159609cc 100644
--- a/Assets/Resources/Materials/Pc.mat
+++ b/Assets/Resources/Materials/Pc.mat
@@ -8,21 +8,21 @@ Material:
   m_PrefabInstance: {fileID: 0}
   m_PrefabAsset: {fileID: 0}
   m_Name: Pc
-  m_Shader: {fileID: 210, guid: 0000000000000000f000000000000000, type: 0}
-  m_ShaderKeywords: _ALPHABLEND_ON _COLORADDSUBDIFF_ON _NORMALMAP
+  m_Shader: {fileID: 211, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: _ALPHATEST_ON _COLORCOLOR_ON
   m_LightmapFlags: 0
   m_EnableInstancingVariants: 0
   m_DoubleSidedGI: 0
-  m_CustomRenderQueue: 3000
+  m_CustomRenderQueue: 2450
   stringTagMap:
-    RenderType: Transparent
+    RenderType: TransparentCutout
   disabledShaderPasses:
   - ALWAYS
   m_SavedProperties:
     serializedVersion: 3
     m_TexEnvs:
     - _BumpMap:
-        m_Texture: {fileID: 2800000, guid: 6b07f0d5b24b9b1468ca57a02e7f96d5, type: 3}
+        m_Texture: {fileID: 0}
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     - _DetailAlbedoMap:
@@ -42,7 +42,7 @@ Material:
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     - _MainTex:
-        m_Texture: {fileID: 10912, guid: 0000000000000000f000000000000000, type: 0}
+        m_Texture: {fileID: 10300, guid: 0000000000000000f000000000000000, type: 0}
         m_Scale: {x: 1, y: 1}
         m_Offset: {x: 0, y: 0}
     - _MetallicGlossMap:
@@ -63,7 +63,7 @@ Material:
     - _CameraFadingEnabled: 0
     - _CameraFarFadeDistance: 2
     - _CameraNearFadeDistance: 1
-    - _ColorMode: 1
+    - _ColorMode: 4
     - _Cull: 2
     - _Cutoff: 0.677
     - _DetailNormalMapScale: 1
@@ -71,15 +71,15 @@ Material:
     - _DistortionEnabled: 0
     - _DistortionStrength: -171.02
     - _DistortionStrengthScaled: -17.102001
-    - _DstBlend: 10
+    - _DstBlend: 0
     - _EmissionEnabled: 0
     - _FlipbookMode: 0
     - _GlossMapScale: 1
     - _Glossiness: 0.2
     - _GlossyReflections: 1
-    - _LightingEnabled: 1
+    - _LightingEnabled: 0
     - _Metallic: 0
-    - _Mode: 2
+    - _Mode: 1
     - _OcclusionStrength: 1
     - _Parallax: 0.02
     - _SmoothnessTextureChannel: 0
@@ -87,12 +87,12 @@ Material:
     - _SoftParticlesFarFadeDistance: 1
     - _SoftParticlesNearFadeDistance: 0
     - _SpecularHighlights: 1
-    - _SrcBlend: 5
+    - _SrcBlend: 1
     - _UVSec: 0
-    - _ZWrite: 0
+    - _ZWrite: 1
     m_Colors:
     - _CameraFadeParams: {r: 0, g: Infinity, b: 0, a: 0}
-    - _Color: {r: 0.865, g: 0.865, b: 0.865, a: 1}
+    - _Color: {r: 0.9433962, g: 0.9433962, b: 0.9433962, a: 1}
     - _ColorAddSubDiff: {r: 1, g: 0, b: 0, a: 0}
     - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
     - _SoftParticleFadeParams: {r: 0, g: 0, b: 0, a: 0}
diff --git a/Assets/Resources/Prefabs/PointCloudParticles.prefab b/Assets/Resources/Prefabs/PointCloudParticles.prefab
index f8ae460033e43e9a4bf24dac1cce15968b2be8e8..392cf149c347bfe54d66468bb01a4b1ac3ccbb62 100644
--- a/Assets/Resources/Prefabs/PointCloudParticles.prefab
+++ b/Assets/Resources/Prefabs/PointCloudParticles.prefab
@@ -4748,7 +4748,7 @@ ParticleSystemRenderer:
   m_EnableGPUInstancing: 1
   m_ApplyActiveColorSpace: 1
   m_AllowRoll: 1
-  m_VertexStreams: 0001030402
+  m_VertexStreams: 000304
   m_Mesh: {fileID: 0}
   m_Mesh1: {fileID: 0}
   m_Mesh2: {fileID: 0}
diff --git a/Assets/Resources/Scenes/RawARCorePointCloudRetriever.unity b/Assets/Resources/Scenes/RawARCorePointCloudRetriever.unity
index e0631693a160b60ee806c6f12792b19e7710764b..d76c82a9e66324ec04690406fa04e556e1ad9954 100644
--- a/Assets/Resources/Scenes/RawARCorePointCloudRetriever.unity
+++ b/Assets/Resources/Scenes/RawARCorePointCloudRetriever.unity
@@ -388,12 +388,11 @@ MonoBehaviour:
   m_EditorClassIdentifier: 
   pointCloud: {fileID: 1157256428}
   maxSqrDistance: 25
-  minConfidence: 0.6875
+  minConfidence: 0.6885
   continueCollectingPoints: 0
   progressBar: {fileID: 553464322}
   progressText: {fileID: 665878184}
   defaultColor: {r: 0.97462785, g: 1, b: 0.27058828, a: 1}
-  weldColor: {r: 0.3529412, g: 0.9372549, b: 0.44705883, a: 1}
   Buttons:
   - {fileID: 1191312876}
   - {fileID: 1458103011}
@@ -401,6 +400,7 @@ MonoBehaviour:
   RenderDistance: 5
   MaxRenderDistance: 6
   RenderSlider: {fileID: 1891182249}
+  weldDistance: 0.025
 --- !u!4 &125579805
 Transform:
   m_ObjectHideFlags: 0
@@ -409,7 +409,7 @@ Transform:
   m_PrefabAsset: {fileID: 0}
   m_GameObject: {fileID: 125579803}
   m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
-  m_LocalPosition: {x: 0.90831095, y: -3.264731, z: 14.116892}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
   m_LocalScale: {x: 1, y: 1, z: 1}
   m_Children:
   - {fileID: 1706220893}
@@ -1068,6 +1068,49 @@ CanvasRenderer:
   m_PrefabAsset: {fileID: 0}
   m_GameObject: {fileID: 519045787}
   m_CullTransparentMesh: 0
+--- !u!1 &522305924
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 522305926}
+  - component: {fileID: 522305925}
+  m_Layer: 0
+  m_Name: Fps
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &522305925
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 522305924}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 905a87ab2b3c59f4abeebb4b006fe010, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+--- !u!4 &522305926
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 522305924}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0.17662245, y: -3.132567, z: -5.5776186}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 12
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
 --- !u!1 &553464321
 GameObject:
   m_ObjectHideFlags: 0
@@ -2819,6 +2862,11 @@ PrefabInstance:
       propertyPath: playOnAwake
       value: 0
       objectReference: {fileID: 0}
+    - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
+        type: 3}
+      propertyPath: ringBufferMode
+      value: 1
+      objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: TrailModule.mode
@@ -2827,7 +2875,7 @@ PrefabInstance:
     - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: moveWithTransform
-      value: 1
+      value: 0
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
@@ -2844,10 +2892,15 @@ PrefabInstance:
       propertyPath: SizeModule.curve.scalar
       value: 2
       objectReference: {fileID: 0}
+    - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
+        type: 3}
+      propertyPath: InitialModule.maxNumParticles
+      value: 300000
+      objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: InitialModule.startSize.scalar
-      value: 0.01875
+      value: 0.02
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
@@ -2857,7 +2910,7 @@ PrefabInstance:
     - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: InitialModule.startLifetime.scalar
-      value: 3600
+      value: 1800
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607645, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
@@ -2957,17 +3010,22 @@ PrefabInstance:
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: m_RenderMode
-      value: 4
+      value: 0
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: m_CastShadows
       value: 0
       objectReference: {fileID: 0}
+    - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
+        type: 3}
+      propertyPath: m_MaskInteraction
+      value: 0
+      objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: m_RenderAlignment
-      value: 2
+      value: 0
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
@@ -2983,21 +3041,21 @@ PrefabInstance:
         type: 3}
       propertyPath: m_Materials.Array.data[0]
       value: 
-      objectReference: {fileID: 2100000, guid: 21228ec852575b74ea71fcaff5bf72cf, type: 2}
+      objectReference: {fileID: 2100000, guid: 43243cadedf4c2d4ea2e9fce4c5c6593, type: 2}
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: m_VertexStreams.Array.size
-      value: 5
+      value: 3
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: m_VertexStreams.Array.data[1]
-      value: 1
+      value: 3
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: m_VertexStreams.Array.data[2]
-      value: 3
+      value: 4
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
@@ -3007,7 +3065,7 @@ PrefabInstance:
     - target: {fileID: 1859515531890607646, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
       propertyPath: m_VertexStreams.Array.data[4]
-      value: 9
+      value: 2
       objectReference: {fileID: 0}
     - target: {fileID: 1859515531890607647, guid: 9b64b381f7cb3be4a9f2dcf1483252b5,
         type: 3}
diff --git a/Assets/Resources/Scripts/MyPointCloudVisualizer.cs b/Assets/Resources/Scripts/MyPointCloudVisualizer.cs
index bf80d34d4fb9bec06f31ff962701537b08dd5302..c456cd62f35cda613a2d2e7ce522ff6e842052f7 100644
--- a/Assets/Resources/Scripts/MyPointCloudVisualizer.cs
+++ b/Assets/Resources/Scripts/MyPointCloudVisualizer.cs
@@ -1,386 +1,457 @@
-п»їusing System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using DataStructures.ViliWonka.KDTree;
-using GoogleARCore;
-using UnityEngine;
-using UnityEngine.UI;
-using Random = UnityEngine.Random;
-
-public class MyPointCloudVisualizer : MonoBehaviour
-{
-    public ParticleSystem pointCloud;
-    [Space(10)] public float maxSqrDistance = 25f;
-    private float maxDistance;
-
-    public float minConfidence = 0.625f;
-    // public float minConfidence = 0.55f;
-    // public float softConfidence = 0.65f;
-
-    private Transform currentCamTransform;
-
-    private ParticleSystem.EmitParams emitParams;
-    private ParticleSystem.EmitParams emitParamsWelded;
-
-    private List<Vector3> points;
-
-    public List<Vector3> Points => points;
-    private KDTree _kdTree = new KDTree();
-    private KDQuery _query = new KDQuery();
-
-    private int minPointsCount = 4600;
-    private float minBoundingBoxVolume = 90f;
-
-    private Vector3 minPoint;
-    private Vector3 maxPoint;
-
-    public bool continueCollectingPoints = false;
-
-
-    [Space(10)] public RectTransform progressBar;
-    private float defaultProgressBarScale;
-    public Text progressText;
-
-    [Space(10)] public Color defaultColor = new Color32(249, 255, 69, 255);
-    public Color weldColor = new Color32(90, 239, 114, 255);
-
-    [Space(10)] public List<Button> Buttons;
-
-    private bool lastConditiondsState = false;
-    private float notificationDelay = 4;
-    private float lastNotificationTime = 0f;
-    public bool CanFinish = true;
-    public float RenderDistance = 5f;
-    public float MaxRenderDistance = 6f;
-    public Slider RenderSlider;
-
-    // Start is called before the first frame update
-    void Start()
-    {
-        points = new List<Vector3>();
-        emitParams = new ParticleSystem.EmitParams();
-        emitParams.startColor = defaultColor;
-
-        emitParamsWelded = new ParticleSystem.EmitParams();
-        emitParamsWelded.startColor = weldColor;
-        emitParamsWelded.startSize = 0.015f;
-
-        defaultProgressBarScale = progressBar.localScale.x;
-        //defaultColor = new Color32(emitParams.startColor.r, emitParams.startColor.g, emitParams.startColor.b, emitParams.startColor.a);
-
-        minPoint = Vector3.positiveInfinity;
-        maxPoint = Vector3.negativeInfinity;
-
-        maxDistance = Mathf.Sqrt(maxSqrDistance);
-
-        foreach (var button in Buttons)
-        {
-            button.interactable = false;
-        }
-
-        lastNotificationTime = Time.time;
-        currentCamTransform = Camera.main.transform;
-
-        RenderSlider.minValue = 0.5f;
-        RenderSlider.maxValue = MaxRenderDistance;
-        RenderSlider.value = RenderDistance;
-        
-
-        StartCoroutine(DelayedStart());
-    }
-
-    public void UpdateRenderDistance(float newVal)
-    {
-        RenderDistance = newVal;
-    }
-
-    private IEnumerator DelayedStart(float delay = 0.05f)
-    {
-        continueCollectingPoints = false;
-        yield return new WaitForSeconds(delay);
-        continueCollectingPoints = true;
-        StartCoroutine(WeldRoutine());
-    }
-
-    // Update is called once per frame
-    void Update()
-    {
-        if (!continueCollectingPoints)
-            return;
-        if (Frame.PointCloud.IsUpdatedThisFrame)
-        {
-            for (int i = 0; i < Frame.PointCloud.PointCount; i++)
-            {
-                var point = Frame.PointCloud.GetPointAsStruct(i);
-                if (point.Confidence < minConfidence) continue;
-                // if (point.Confidence < softConfidence && Random.Range(0f, 1f) < 0.25f) continue;
-
-                var distance = (currentCamTransform.position - point.Position).sqrMagnitude;
-                if (distance > maxSqrDistance) continue;
-
-                emitParams.position = point.Position;
-                pointCloud.Emit(emitParams, 1);
-                points.Add(point.Position);
-                if (!(Random.Range(0f, 1f) < 0.2f)) continue;
-                if (point.Position.x < minPoint.x)
-                    minPoint.x = point.Position.x;
-                if (point.Position.y < minPoint.y)
-                    minPoint.y = point.Position.y;
-                if (point.Position.z < minPoint.z)
-                    minPoint.z = point.Position.z;
-
-                if (point.Position.x > maxPoint.x)
-                    maxPoint.x = point.Position.x;
-                if (point.Position.y > maxPoint.y)
-                    maxPoint.y = point.Position.y;
-                if (point.Position.z > maxPoint.z)
-                    maxPoint.z = point.Position.z;
-            }
-        }
-
-        var currentConditionsState = CheckFinishConditionsSatisfied();
-        // сохранение и отправка
-        if (currentConditionsState)
-        {
-            if (currentConditionsState != lastConditiondsState)
-            {
-                var curTime = Time.time;
-                if (curTime - lastNotificationTime > notificationDelay)
-                {
-                    lastNotificationTime = curTime;
-                    NotificationManager.instance.CreateNotification(
-                        "Собрано достаточно точек - можно продолжать сканирование или отправить их на сервер");
-                }
-            }
-
-            foreach (var button in Buttons)
-            {
-                button.interactable = true;
-            }
-        }
-        else
-        {
-            foreach (var button in Buttons)
-            {
-                button.interactable = false;
-            }
-        }
-
-        lastConditiondsState = currentConditionsState;
-
-        UpdateUI();
-    }
-
-    private bool CheckFinishConditionsSatisfied()
-    {
-        return CanFinish && CheckBoundingBox() && points.Count >= minPointsCount;
-    }
-
-    private float CalculateCurrentBoundingBoxVolume()
-    {
-//        print($"{minPoint}, {maxPoint}");
-        var diag = maxPoint - minPoint;
-        return Mathf.Abs(diag.x * diag.y * diag.z);
-    }
-
-    private bool CheckBoundingBox()
-    {
-        return CalculateCurrentBoundingBoxVolume() >= minBoundingBoxVolume;
-    }
-
-    private IEnumerator WeldRoutine(float maxRadius = 0.01125f, float uniformPart = 0.4f, int maxSamples = 400, int maxSamplesPerFrame = 150)
-    {
-        var extendedMaxSamplesPerFrame = maxSamplesPerFrame * 2;
-        var counter = 0;
-        List<int> nearestPointsInd = new List<int>();
-        List<int> results = new List<int>();
-        List<int> samples = new List<int>();
-        var weldMask = new List<bool>(points.Count);
-        while (true)
-        {
-            if (!gameObject.activeInHierarchy ||
-                points.Count == 0 ||
-                uniformPart <= 0f)
-                yield return null;
-            
-            _kdTree.Build(points, 32);
-            nearestPointsInd.Clear();
-            _query.Radius(_kdTree, currentCamTransform.position, maxDistance + 0.1f, nearestPointsInd);
-            
-            samples.Clear();
-            
-            var numSamples = (int) (nearestPointsInd.Count * uniformPart) + 1;
-            numSamples = Math.Min(numSamples, maxSamples);
-            var probNum = numSamples;
-
-            for (var i = 0; i < nearestPointsInd.Count; i++)
-            {
-                var probability = probNum * 1.0f / nearestPointsInd.Count;
-                if (Random.Range(0f, 1f) < probability)
-                {
-                    probNum -= 1;
-                    samples.Add(nearestPointsInd[i]);
-                }
-
-                if (samples.Count > numSamples * 1.2f)
-                    break;
-            }
-            yield return null;
-            
-            weldMask.Clear();
-            for (int i = 0; i < points.Count; i++)
-            {
-                counter++;
-                weldMask.Add(false);
-                if (counter > extendedMaxSamplesPerFrame)
-                {
-                    yield return null;
-                    counter = 0;
-                }
-            }
-            
-
-            results.Clear();
-            foreach (var sampleInd in samples)
-            {
-                counter++;
-                var point = points[sampleInd];
-                _query.Radius(_kdTree, point, maxRadius*0.9f, results);
-                // yield return null;
-                if (results.Count > 1) // 1 is point itself; 2 is neighbour
-                    weldMask[sampleInd] = true;
-                results.Clear();
-                if (counter > maxSamplesPerFrame)
-                {
-                    yield return null;
-                    counter = 0;
-                }
-            }
-
-            
-            for (int i = weldMask.Count - 1; i > -1; i--)
-            {
-                counter++;
-                // print($"i:{i}, mask_len:{weldMask.Count}");
-                if (weldMask[i])
-                {
-                    points.RemoveAt(i);
-                }
-                if (counter > maxSamplesPerFrame)
-                {
-                    yield return null;
-                    counter = 0;
-                }
-            }
-            results.Clear();
-            _kdTree.Build(points);
-            _query.Radius(_kdTree, currentCamTransform.position, RenderDistance, results);
-            
-            pointCloud.Clear();
-            foreach (var pointInd in results)
-            {
-                if (Random.Range(0.0f, 1.0f) < 0.75)
-                {
-                    continue;
-                }
-                counter++;
-                emitParamsWelded.position = points[pointInd];
-                pointCloud.Emit(emitParamsWelded, 1);
-                if (counter > extendedMaxSamplesPerFrame)
-                {
-                    yield return null;
-                    counter = 0;
-                }
-            }
-            results.Clear();
-            yield return null;
-        }
-    }
-    
-    private void WeldPoints(float maxRadius = 0.015f, float uniformPart = 0.45f, int maxSamples = 1200)
-    {
-        if (points.Count == 0 ||
-            uniformPart <= 0f)
-        {
-            return;
-        }
-
-        var oldCount = points.Count;
-        _kdTree.Build(points);
-
-
-        List<int> nearestPointsInd = new List<int>();
-        _query.Radius(_kdTree, currentCamTransform.position, maxDistance + 0.1f, nearestPointsInd);
-
-
-        List<int> results = new List<int>();
-        List<int> samples = new List<int>();
-        var numSamples = (int) (nearestPointsInd.Count * uniformPart) + 1;
-        numSamples = Math.Min(numSamples, maxSamples);
-        var probNum = numSamples;
-        for (var i = 0; i < nearestPointsInd.Count; i++)
-        {
-            var probability = probNum * 1.0f / nearestPointsInd.Count;
-            if (Random.Range(0f, 1f) < probability)
-            {
-                probNum -= 1;
-                samples.Add(nearestPointsInd[i]);
-            }
-
-            if (samples.Count > numSamples * 1.2f)
-                break;
-        }
-
-        print(samples.Count);
-
-        var weldMask = new List<bool>(points.Count);
-        for (int i = 0; i < points.Count; i++)
-            weldMask.Add(false);
-
-        foreach (var sampleInd in samples)
-        {
-            var point = points[sampleInd];
-            _query.Radius(_kdTree, point, maxRadius*0.9f, results);
-            if (results.Count > 1) // 1 is point itself; 2 is neighbour
-                weldMask[sampleInd] = true;
-            results.Clear();
-        }
-
-
-        pointCloud.Clear();
-        for (int i = points.Count - 1; i > -1; i--)
-        {
-            if (weldMask[i])
-            {
-                points.RemoveAt(i);
-            }
-        }
-        results.Clear();
-        _kdTree.Build(points);
-        _query.Radius(_kdTree, currentCamTransform.position, maxDistance, results);
-        foreach (var pointInd in results)
-        {
-            emitParamsWelded.position = points[pointInd];
-            pointCloud.Emit(emitParamsWelded, 1);
-        }
-
-        // NotificationManager.instance.CreateNotification($"Удалено {points.Count - oldCount} похожих точек\n" +
-        //                                                 $"Отображено {results.Count}/{points.Count}", 2f);
-    }
-
-
-    private void UpdateUI()
-    {
-        var pointsRatio = Mathf.Clamp01(1f * points.Count / minPointsCount);
-        var bbVol = CalculateCurrentBoundingBoxVolume();
-        var volumeRatio = Mathf.Clamp01(bbVol / minBoundingBoxVolume);
-
-        var ratio = (pointsRatio + volumeRatio) / 2f;
-
-        progressBar.localScale = new Vector3(ratio, 1f, 1f);
-        progressText.text =
-            $"{points.Count}/{minPointsCount} points | {Math.Round(bbVol, 1)}/{minBoundingBoxVolume} m3";
-    }
+п»їusing System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using DataStructures.ViliWonka.KDTree;
+using GoogleARCore;
+using UnityEngine;
+using UnityEngine.UI;
+using Random = UnityEngine.Random;
+
+public class MyPointCloudVisualizer : MonoBehaviour
+{
+    public ParticleSystem pointCloud;
+    [Space(10)] public float maxSqrDistance = 25f;
+    private float maxDistance;
+
+    public float minConfidence = 0.625f;
+    // public float minConfidence = 0.55f;
+    // public float softConfidence = 0.65f;
+
+    private Transform currentCamTransform;
+
+    private ParticleSystem.EmitParams emitParams;
+
+    private KDTree globalPoints = new KDTree();
+    private KDTree localPoints = new KDTree();
+    private KDQuery interQuery = new KDQuery();
+    
+    private List<Vector3> pointsToAdd;
+
+    //private List<Vector3> points;
+
+    public List<Vector3> Points => new List<Vector3>(globalPoints.Points);
+
+    private int minPointsCount = 4600;
+    private float minBoundingBoxVolume = 90f;
+
+    private Vector3 minPoint;
+    private Vector3 maxPoint;
+    private Vector3 oldPos;
+
+    public bool continueCollectingPoints = false;
+
+
+    [Space(10)] public RectTransform progressBar;
+    public Text progressText;
+
+    [Space(10)] public Color defaultColor = new Color32(249, 255, 69, 255);
+
+    [Space(10)] public List<Button> Buttons;
+
+    private bool lastConditiondsState = false;
+    private float notificationDelay = 4;
+    private float lastNotificationTime = 0f;
+    public bool CanFinish = true;
+    public float RenderDistance = 5f;
+    public float MaxRenderDistance = 6f;
+    public Slider RenderSlider;
+    public float weldDistance = 0.015f;
+
+    // Start is called before the first frame update
+    void Start()
+    {
+        pointsToAdd = new List<Vector3>();
+        emitParams = new ParticleSystem.EmitParams();
+        emitParams.startColor = defaultColor;
+
+        minPoint = Vector3.positiveInfinity;
+        maxPoint = Vector3.negativeInfinity;
+
+        maxDistance = Mathf.Sqrt(maxSqrDistance);
+
+        foreach (var button in Buttons)
+        {
+            button.interactable = false;
+        }
+
+        lastNotificationTime = Time.time;
+        currentCamTransform = Camera.main.transform;
+
+        RenderSlider.minValue = 0.5f;
+        RenderSlider.maxValue = MaxRenderDistance;
+        RenderSlider.value = RenderDistance;
+        oldPos = currentCamTransform.position;
+
+        StartCoroutine(DelayedStart());
+    }
+
+    public void UpdateRenderDistance(float newVal)
+    {
+        RenderDistance = newVal;
+    }
+
+    private IEnumerator DelayedStart(float delay = 0.05f)
+    {
+        continueCollectingPoints = false;
+        yield return new WaitForSeconds(delay);
+        continueCollectingPoints = true;
+    }
+
+    void Rerender()
+    {
+        pointCloud.Clear();
+
+        foreach (var point in localPoints.Points)
+        {
+            emitParams.position = point;
+            pointCloud.Emit(emitParams, 1);
+        }
+        oldPos = currentCamTransform.position;
+    }
+
+    void RotatePoints()
+    {
+        var newPoints = new List<Vector3>(globalPoints.Points);
+        newPoints.AddRange(pointsToAdd);
+
+        globalPoints.Build(newPoints);
+        CreateLocalKD();
+        foreach (var point in pointsToAdd)
+        {
+            if (!(Random.Range(0f, 1f) < 0.4f)) continue;
+            if (point.x < minPoint.x)
+                minPoint.x = point.x;
+            if (point.y < minPoint.y)
+                minPoint.y = point.y;
+            if (point.z < minPoint.z)
+                minPoint.z = point.z;
+
+            if (point.x > maxPoint.x)
+                maxPoint.x = point.x;
+            if (point.y > maxPoint.y)
+                maxPoint.y = point.y;
+            if (point.z > maxPoint.z)
+                maxPoint.z = point.z;
+        }
+        
+        pointsToAdd.Clear();
+    }
+
+    void CreateLocalKD()
+    {
+        if (globalPoints.Count == 0)
+        {
+            localPoints.Build(new List<Vector3>());
+            return;
+        }
+        List<int> nearestPointsInd = new List<int>();
+        interQuery.Radius(globalPoints, currentCamTransform.position, maxDistance + 0.1f, nearestPointsInd);
+        var localPointsList = new List<Vector3>();
+        foreach (var pInd in nearestPointsInd)
+        {
+            localPointsList.Add(globalPoints.Points[pInd]);
+        }
+        
+        localPoints.Build(localPointsList);
+    }
+
+    // Update is called once per frame
+    void Update()
+    {
+        if (!continueCollectingPoints)
+            return;
+        
+        
+        if (Frame.PointCloud.IsUpdatedThisFrame)
+        {
+            if (pointsToAdd.Count > 400)
+            {
+                RotatePoints();
+            }
+            else if (Random.Range(0f, 1f) < 0.0115f || (oldPos - currentCamTransform.position).sqrMagnitude > 1)
+            {
+                CreateLocalKD();
+                Rerender();
+            }
+            
+            List<int> queryResults = new List<int>();
+            for (int i = 0; i < Frame.PointCloud.PointCount; i++)
+            {
+                queryResults.Clear();
+                
+                var point = Frame.PointCloud.GetPointAsStruct(i);
+                if (point.Confidence < minConfidence) continue;
+                // if (point.Confidence < softConfidence && Random.Range(0f, 1f) < 0.25f) continue;
+
+                var distance = (currentCamTransform.position - point.Position).sqrMagnitude;
+                if (distance > maxSqrDistance) continue;
+                
+                // compare against localkd
+                if (localPoints.Count > 0)
+                {
+                    interQuery.Radius(localPoints, point.Position, weldDistance, queryResults);
+                    if (queryResults.Count > 0)
+                    {
+                        continue;
+                    }
+                }
+
+                //add to pointsToAdd
+
+                
+                if (Random.Range(0f, 1f) < 0.35f)
+                {
+                    emitParams.position = point;
+                    pointCloud.Emit(emitParams, 1);
+                }
+
+                pointsToAdd.Add(point.Position);
+            }
+        }
+
+        var currentConditionsState = CheckFinishConditionsSatisfied();
+        // сохранение и отправка
+        if (currentConditionsState)
+        {
+            if (currentConditionsState != lastConditiondsState)
+            {
+                var curTime = Time.time;
+                if (curTime - lastNotificationTime > notificationDelay)
+                {
+                    lastNotificationTime = curTime;
+                    NotificationManager.instance.CreateNotification(
+                        "Собрано достаточно точек - можно продолжать сканирование или отправить их на сервер");
+                }
+            }
+
+            foreach (var button in Buttons)
+            {
+                button.interactable = true;
+            }
+        }
+        else
+        {
+            foreach (var button in Buttons)
+            {
+                button.interactable = false;
+            }
+        }
+
+        lastConditiondsState = currentConditionsState;
+
+        UpdateUI();
+    }
+
+    private bool CheckFinishConditionsSatisfied()
+    {
+        return CanFinish && CheckBoundingBox() && globalPoints.Count >= minPointsCount;
+    }
+
+    private float CalculateCurrentBoundingBoxVolume()
+    {
+//        print($"{minPoint}, {maxPoint}");
+        var diag = maxPoint - minPoint;
+        return Mathf.Abs(diag.x * diag.y * diag.z);
+    }
+
+    private bool CheckBoundingBox()
+    {
+        return CalculateCurrentBoundingBoxVolume() >= minBoundingBoxVolume;
+    }
+
+    // private IEnumerator WeldRoutine(float maxRadius = 0.01125f, float uniformPart = 0.4f, int maxSamples = 400, int maxSamplesPerFrame = 150)
+    // {
+    //     var extendedMaxSamplesPerFrame = maxSamplesPerFrame * 2;
+    //     var counter = 0;
+    //     List<int> nearestPointsInd = new List<int>();
+    //     List<int> results = new List<int>();
+    //     List<int> samples = new List<int>();
+    //     var weldMask = new List<bool>(points.Count);
+    //     while (true)
+    //     {
+    //         if (!gameObject.activeInHierarchy ||
+    //             points.Count == 0 ||
+    //             uniformPart <= 0f)
+    //             yield return null;
+    //         
+    //         _kdTree.Build(points, 32);
+    //         nearestPointsInd.Clear();
+    //         _query.Radius(_kdTree, currentCamTransform.position, maxDistance + 0.1f, nearestPointsInd);
+    //         
+    //         samples.Clear();
+    //         
+    //         var numSamples = (int) (nearestPointsInd.Count * uniformPart) + 1;
+    //         numSamples = Math.Min(numSamples, maxSamples);
+    //         var probNum = numSamples;
+    //
+    //         for (var i = 0; i < nearestPointsInd.Count; i++)
+    //         {
+    //             var probability = probNum * 1.0f / nearestPointsInd.Count;
+    //             if (Random.Range(0f, 1f) < probability)
+    //             {
+    //                 probNum -= 1;
+    //                 samples.Add(nearestPointsInd[i]);
+    //             }
+    //
+    //             if (samples.Count > numSamples * 1.2f)
+    //                 break;
+    //         }
+    //         yield return null;
+    //         
+    //         weldMask.Clear();
+    //         for (int i = 0; i < points.Count; i++)
+    //         {
+    //             counter++;
+    //             weldMask.Add(false);
+    //             if (counter > extendedMaxSamplesPerFrame)
+    //             {
+    //                 yield return null;
+    //                 counter = 0;
+    //             }
+    //         }
+    //         
+    //
+    //         results.Clear();
+    //         foreach (var sampleInd in samples)
+    //         {
+    //             counter++;
+    //             var point = points[sampleInd];
+    //             _query.Radius(_kdTree, point, maxRadius*0.9f, results);
+    //             // yield return null;
+    //             if (results.Count > 1) // 1 is point itself; 2 is neighbour
+    //                 weldMask[sampleInd] = true;
+    //             results.Clear();
+    //             if (counter > maxSamplesPerFrame)
+    //             {
+    //                 yield return null;
+    //                 counter = 0;
+    //             }
+    //         }
+    //
+    //         
+    //         for (int i = weldMask.Count - 1; i > -1; i--)
+    //         {
+    //             counter++;
+    //             // print($"i:{i}, mask_len:{weldMask.Count}");
+    //             if (weldMask[i])
+    //             {
+    //                 points.RemoveAt(i);
+    //             }
+    //             if (counter > maxSamplesPerFrame)
+    //             {
+    //                 yield return null;
+    //                 counter = 0;
+    //             }
+    //         }
+    //         results.Clear();
+    //         _kdTree.Build(points);
+    //         _query.Radius(_kdTree, currentCamTransform.position, RenderDistance, results);
+    //         
+    //         pointCloud.Clear();
+    //         foreach (var pointInd in results)
+    //         {
+    //             if (Random.Range(0.0f, 1.0f) < 0.75)
+    //             {
+    //                 continue;
+    //             }
+    //             counter++;
+    //             emitParamsWelded.position = points[pointInd];
+    //             pointCloud.Emit(emitParamsWelded, 1);
+    //             if (counter > extendedMaxSamplesPerFrame)
+    //             {
+    //                 yield return null;
+    //                 counter = 0;
+    //             }
+    //         }
+    //         results.Clear();
+    //         yield return null;
+    //     }
+    // }
+    //
+    // private void WeldPoints(float maxRadius = 0.015f, float uniformPart = 0.45f, int maxSamples = 1200)
+    // {
+    //     if (points.Count == 0 ||
+    //         uniformPart <= 0f)
+    //     {
+    //         return;
+    //     }
+    //
+    //     var oldCount = points.Count;
+    //     _kdTree.Build(points);
+    //
+    //
+    //     List<int> nearestPointsInd = new List<int>();
+    //     _query.Radius(_kdTree, currentCamTransform.position, maxDistance + 0.1f, nearestPointsInd);
+    //
+    //
+    //     List<int> results = new List<int>();
+    //     List<int> samples = new List<int>();
+    //     var numSamples = (int) (nearestPointsInd.Count * uniformPart) + 1;
+    //     numSamples = Math.Min(numSamples, maxSamples);
+    //     var probNum = numSamples;
+    //     for (var i = 0; i < nearestPointsInd.Count; i++)
+    //     {
+    //         var probability = probNum * 1.0f / nearestPointsInd.Count;
+    //         if (Random.Range(0f, 1f) < probability)
+    //         {
+    //             probNum -= 1;
+    //             samples.Add(nearestPointsInd[i]);
+    //         }
+    //
+    //         if (samples.Count > numSamples * 1.2f)
+    //             break;
+    //     }
+    //
+    //     print(samples.Count);
+    //
+    //     var weldMask = new List<bool>(points.Count);
+    //     for (int i = 0; i < points.Count; i++)
+    //         weldMask.Add(false);
+    //
+    //     foreach (var sampleInd in samples)
+    //     {
+    //         var point = points[sampleInd];
+    //         _query.Radius(_kdTree, point, maxRadius*0.9f, results);
+    //         if (results.Count > 1) // 1 is point itself; 2 is neighbour
+    //             weldMask[sampleInd] = true;
+    //         results.Clear();
+    //     }
+    //
+    //
+    //     pointCloud.Clear();
+    //     for (int i = points.Count - 1; i > -1; i--)
+    //     {
+    //         if (weldMask[i])
+    //         {
+    //             points.RemoveAt(i);
+    //         }
+    //     }
+    //     results.Clear();
+    //     _kdTree.Build(points);
+    //     _query.Radius(_kdTree, currentCamTransform.position, maxDistance, results);
+    //     foreach (var pointInd in results)
+    //     {
+    //         emitParamsWelded.position = points[pointInd];
+    //         pointCloud.Emit(emitParamsWelded, 1);
+    //     }
+    //
+    //     // NotificationManager.instance.CreateNotification($"Удалено {points.Count - oldCount} похожих точек\n" +
+    //     //                                                 $"Отображено {results.Count}/{points.Count}", 2f);
+    // }
+    //
+
+    private void UpdateUI()
+    {
+        var pointsRatio = Mathf.Clamp01(1f * globalPoints.Count / minPointsCount);
+        var bbVol = CalculateCurrentBoundingBoxVolume();
+        var volumeRatio = Mathf.Clamp01(bbVol / minBoundingBoxVolume);
+
+        var ratio = (pointsRatio + volumeRatio) / 2f;
+
+        progressBar.localScale = new Vector3(ratio, 1f, 1f);
+        progressText.text =
+            $"{globalPoints.Count}/{minPointsCount} points | {Math.Round(bbVol, 1)}/{minBoundingBoxVolume} m3";
+    }
 }
\ No newline at end of file
diff --git a/Assets/Resources/Scripts/PointCloudSender.cs b/Assets/Resources/Scripts/PointCloudSender.cs
index 6b4c3835165e13bd6c2c7ce32116aeb9c92f818c..c3434e620525e86040b58acf02476316306ef5e5 100644
--- a/Assets/Resources/Scripts/PointCloudSender.cs
+++ b/Assets/Resources/Scripts/PointCloudSender.cs
@@ -1,200 +1,200 @@
-п»їusing System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using UnityEngine;
-using UnityEngine.Networking;
-using UnityEngine.UI;
-
-public class PointCloudSender : MonoBehaviour
-{
-    public InputField host;
-    public GameObject RemoteMarker;
-
-    private PointCloudSaver _pointCloudSaver;
-    private MyPointCloudVisualizer _pointCloudVisualizer;
-
-    void Start()
-    {
-        _pointCloudSaver = GetComponent<PointCloudSaver>();
-        _pointCloudVisualizer = GetComponent<MyPointCloudVisualizer>();
-        NotificationManager.instance.CreateNotification("Система работает", 5f);
-    }
-
-    private string GetUrl(string sendType)
-    {
-        var hostAddr = host.text;
-        var url = hostAddr + "/" + sendType;
-        return url;
-    }
-
-    private string SaveCurrentPointCloud()
-    {
-        var points = _pointCloudVisualizer.Points;
-        var filename = _pointCloudSaver.SavePointCloud(points);
-        NotificationManager.instance.CreateNotification("Облако точек сохранено");
-        return filename;
-    }
-
-    public void SendAsMap()
-    {
-        var filename = SaveCurrentPointCloud();
-        SendAsMap(filename);
-    }
-
-    public void SendAsMap(string filename)
-    {
-        StartCoroutine(SendAsMapRoutine(filename));
-    }
-
-    private IEnumerator Note()
-    {
-        yield return new WaitForSeconds(15f);
-        NotificationManager.instance.CreateNotification(
-            "Обработка может занять длительное время, пожалуйста, подождите");
-        while (true)
-        {
-            yield return new WaitForSeconds(15f);
-            NotificationManager.instance.CreateNotification(
-                "Сервер всё еще обрабатывает ваш запрос, пожалуйста, подождите");
-        }
-    }
-
-    private IEnumerator SendAsMapRoutine(string filename)
-    {
-        var url = GetUrl("addmap");
-        List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
-
-
-        var bytePointCloud = File.ReadAllBytes(filename);
-        formData.Add(new MultipartFormFileSection(
-            "pointCloud", bytePointCloud, "MapPointCloud.xyz", "text/plain"));
-
-        List<Vector3> armarkers = new List<Vector3>();
-        foreach (var markerTransform in ARMarker.instances)
-        {
-            var pos = markerTransform.position;
-            armarkers.Add(pos);
-        }
-
-        if (armarkers.Count > 0)
-        {
-            var markersFile = _pointCloudSaver.SavePointCloud(armarkers, "ar_markers.txt");
-            var byteMarkers = File.ReadAllBytes(markersFile);
-            formData.Add(new MultipartFormFileSection(
-                "markers", byteMarkers, "Markers.xyz", "text/plain"));
-        }
-
-
-        UnityWebRequest www = UnityWebRequest.Post(url, formData);
-        var routine = StartCoroutine(Note());
-        foreach (var button in _pointCloudVisualizer.Buttons)
-        {
-            button.interactable = false;
-        }
-        _pointCloudVisualizer.CanFinish = false;
-
-        NotificationManager.instance.CreateNotification("Сервер начал думать над вашим запросом");
-        yield return www.SendWebRequest();
-        StopCoroutine(routine);
-        foreach (var button in _pointCloudVisualizer.Buttons)
-        {
-            button.interactable = true;
-        }
-        _pointCloudVisualizer.CanFinish = true;
-
-        if (www.isNetworkError)
-        {
-            NotificationManager.instance.CreateNotification("Сервер недоступен, проверьте соединение");
-        }
-        else if (www.isHttpError)
-        {
-            Debug.Log(www.error);
-            NotificationManager.instance.CreateNotification("Ошибка сервера, не удалось создать карту");
-        }
-        else
-        {
-            NotificationManager.instance.CreateNotification("Карта создана успешно");
-        }
-    }
-
-    public void SendAsAlign()
-    {
-        var filename = SaveCurrentPointCloud();
-        SendAsAlign(filename);
-    }
-
-    public void SendAsAlign(string filename)
-    {
-        StartCoroutine(SendAsAlignRoutine(filename));
-    }
-
-    private IEnumerator SendAsAlignRoutine(string filename)
-    {
-        var url = GetUrl("align");
-        List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
-        formData.Add(new MultipartFormDataSection("targetMap=1"));
-
-        var bytePointCloud = File.ReadAllBytes(filename);
-        formData.Add(new MultipartFormFileSection(
-            "pointCloud", bytePointCloud, "MapPointCloud.xyz", "text/plain"));
-
-        UnityWebRequest www = UnityWebRequest.Post(url, formData);
-        var routine = StartCoroutine(Note());
-        foreach (var button in _pointCloudVisualizer.Buttons)
-        {
-            button.interactable = false;
-        }
-        _pointCloudVisualizer.CanFinish = false;
-
-        NotificationManager.instance.CreateNotification("Сервер начал думать над вашим запросом");
-        yield return www.SendWebRequest();
-        StopCoroutine(routine);
-        foreach (var button in _pointCloudVisualizer.Buttons)
-        {
-            button.interactable = true;
-        }
-        _pointCloudVisualizer.CanFinish = true;
-
-        if (www.isNetworkError)
-        {
-            NotificationManager.instance.CreateNotification("Сервер недоступен, проверьте соединение");
-            yield break;
-        }
-
-        if (www.isHttpError)
-        {
-            Debug.Log(www.error);
-            NotificationManager.instance.CreateNotification("Ошибка сервера, не удалось локализоваться");
-            yield break;
-        }
-
-        //x y z\nx y z...
-        var resp = www.downloadHandler.text.Split('\n');
-        foreach (var strVec in resp)
-        {
-            var splitted = strVec.Split(' ');
-            var pos = new Vector3(
-                float.Parse(splitted[0], CultureInfo.InvariantCulture),
-                float.Parse(splitted[1], CultureInfo.InvariantCulture),
-                float.Parse(splitted[2], CultureInfo.InvariantCulture));
-            Instantiate(RemoteMarker, pos, Quaternion.identity);
-        }
-
-        NotificationManager.instance.CreateNotification("Локализация прошла успешно");
-
-        // var translationFl = new float[3];
-        // for (var i = 0; i < translationStr.Count; i++)
-        // {
-        //     var coord = float.Parse(translationStr);
-        //     translationFl[i] = coord;
-        // }
-        //
-        // var rotationFl = new float[4];
-        // foreach (var coordStr in translationStr)
-        // {
-        //     rotationFl[i] = float.Parse(coordStr);
-        // }
-    }
+п»їusing System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using UnityEngine;
+using UnityEngine.Networking;
+using UnityEngine.UI;
+
+public class PointCloudSender : MonoBehaviour
+{
+    public InputField host;
+    public GameObject RemoteMarker;
+
+    private PointCloudSaver _pointCloudSaver;
+    private MyPointCloudVisualizer _pointCloudVisualizer;
+
+    void Start()
+    {
+        _pointCloudSaver = GetComponent<PointCloudSaver>();
+        _pointCloudVisualizer = GetComponent<MyPointCloudVisualizer>();
+        NotificationManager.instance.CreateNotification("Система работает", 5f);
+    }
+
+    private string GetUrl(string sendType)
+    {
+        var hostAddr = host.text;
+        var url = hostAddr + "/" + sendType;
+        return url;
+    }
+
+    private string SaveCurrentPointCloud()
+    {
+        var points = _pointCloudVisualizer.Points;
+        var filename = _pointCloudSaver.SavePointCloud(points);
+        NotificationManager.instance.CreateNotification("Облако точек сохранено");
+        return filename;
+    }
+
+    public void SendAsMap()
+    {
+        var filename = SaveCurrentPointCloud();
+        SendAsMap(filename);
+    }
+
+    public void SendAsMap(string filename)
+    {
+        StartCoroutine(SendAsMapRoutine(filename));
+    }
+
+    private IEnumerator Note()
+    {
+        yield return new WaitForSeconds(15f);
+        NotificationManager.instance.CreateNotification(
+            "Обработка может занять длительное время, пожалуйста, подождите");
+        while (true)
+        {
+            yield return new WaitForSeconds(15f);
+            NotificationManager.instance.CreateNotification(
+                "Сервер всё еще обрабатывает ваш запрос, пожалуйста, подождите");
+        }
+    }
+
+    private IEnumerator SendAsMapRoutine(string filename)
+    {
+        var url = GetUrl("addmap");
+        List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
+
+
+        var bytePointCloud = File.ReadAllBytes(filename);
+        formData.Add(new MultipartFormFileSection(
+            "pointCloud", bytePointCloud, "MapPointCloud.xyz", "text/plain"));
+
+        List<Vector3> armarkers = new List<Vector3>();
+        foreach (var markerTransform in ARMarker.instances)
+        {
+            var pos = markerTransform.position;
+            armarkers.Add(pos);
+        }
+
+        if (armarkers.Count > 0)
+        {
+            var markersFile = _pointCloudSaver.SavePointCloud(armarkers, "ar_markers.txt");
+            var byteMarkers = File.ReadAllBytes(markersFile);
+            formData.Add(new MultipartFormFileSection(
+                "markers", byteMarkers, "Markers.xyz", "text/plain"));
+        }
+
+
+        UnityWebRequest www = UnityWebRequest.Post(url, formData);
+        var routine = StartCoroutine(Note());
+        foreach (var button in _pointCloudVisualizer.Buttons)
+        {
+            button.interactable = false;
+        }
+        _pointCloudVisualizer.CanFinish = false;
+
+        NotificationManager.instance.CreateNotification("Сервер начал думать над вашим запросом");
+        yield return www.SendWebRequest();
+        StopCoroutine(routine);
+        foreach (var button in _pointCloudVisualizer.Buttons)
+        {
+            button.interactable = true;
+        }
+        _pointCloudVisualizer.CanFinish = true;
+
+        if (www.isNetworkError)
+        {
+            NotificationManager.instance.CreateNotification("Сервер недоступен, проверьте соединение");
+        }
+        else if (www.isHttpError)
+        {
+            Debug.Log(www.error);
+            NotificationManager.instance.CreateNotification("Ошибка сервера, не удалось создать карту");
+        }
+        else
+        {
+            NotificationManager.instance.CreateNotification("Карта создана успешно");
+        }
+    }
+
+    public void SendAsAlign()
+    {
+        var filename = SaveCurrentPointCloud();
+        SendAsAlign(filename);
+    }
+
+    public void SendAsAlign(string filename)
+    {
+        StartCoroutine(SendAsAlignRoutine(filename));
+    }
+
+    private IEnumerator SendAsAlignRoutine(string filename)
+    {
+        var url = GetUrl("align");
+        List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
+        formData.Add(new MultipartFormDataSection("targetMap=1"));
+
+        var bytePointCloud = File.ReadAllBytes(filename);
+        formData.Add(new MultipartFormFileSection(
+            "pointCloud", bytePointCloud, "MapPointCloud.xyz", "text/plain"));
+
+        UnityWebRequest www = UnityWebRequest.Post(url, formData);
+        var routine = StartCoroutine(Note());
+        foreach (var button in _pointCloudVisualizer.Buttons)
+        {
+            button.interactable = false;
+        }
+        _pointCloudVisualizer.CanFinish = false;
+
+        NotificationManager.instance.CreateNotification("Сервер начал думать над вашим запросом");
+        yield return www.SendWebRequest();
+        StopCoroutine(routine);
+        foreach (var button in _pointCloudVisualizer.Buttons)
+        {
+            button.interactable = true;
+        }
+        _pointCloudVisualizer.CanFinish = true;
+
+        if (www.isNetworkError)
+        {
+            NotificationManager.instance.CreateNotification("Сервер недоступен, проверьте соединение");
+            yield break;
+        }
+
+        if (www.isHttpError)
+        {
+            Debug.Log(www.error);
+            NotificationManager.instance.CreateNotification("Ошибка сервера, не удалось локализоваться");
+            yield break;
+        }
+
+        //x y z\nx y z...
+        var resp = www.downloadHandler.text.Split('\n');
+        foreach (var strVec in resp)
+        {
+            var splitted = strVec.Split(' ');
+            var pos = new Vector3(
+                float.Parse(splitted[0], CultureInfo.InvariantCulture),
+                float.Parse(splitted[1], CultureInfo.InvariantCulture),
+                float.Parse(splitted[2], CultureInfo.InvariantCulture));
+            Instantiate(RemoteMarker, pos, Quaternion.identity);
+        }
+
+        NotificationManager.instance.CreateNotification("Локализация прошла успешно");
+
+        // var translationFl = new float[3];
+        // for (var i = 0; i < translationStr.Count; i++)
+        // {
+        //     var coord = float.Parse(translationStr);
+        //     translationFl[i] = coord;
+        // }
+        //
+        // var rotationFl = new float[4];
+        // foreach (var coordStr in translationStr)
+        // {
+        //     rotationFl[i] = float.Parse(coordStr);
+        // }
+    }
 }
\ No newline at end of file