@terraware/web-components 4.2.26-rc.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_vendor/react-multi-carousel/index.js +13 -0
- package/_vendor/react-multi-carousel/lib/Arrows.js +13 -0
- package/_vendor/react-multi-carousel/lib/Carousel.js +19 -0
- package/_vendor/react-multi-carousel/lib/CarouselItems.js +14 -0
- package/_vendor/react-multi-carousel/lib/Dots.js +16 -0
- package/_vendor/react-multi-carousel/lib/index.js +13 -0
- package/_vendor/react-multi-carousel/lib/types.js +13 -0
- package/_vendor/react-multi-carousel/lib/utils/clones.js +14 -0
- package/_vendor/react-multi-carousel/lib/utils/common.js +13 -0
- package/_vendor/react-multi-carousel/lib/utils/dots.js +14 -0
- package/_vendor/react-multi-carousel/lib/utils/elementWidth.js +12 -0
- package/_vendor/react-multi-carousel/lib/utils/index.js +20 -0
- package/_vendor/react-multi-carousel/lib/utils/mouseOrTouchMove.js +14 -0
- package/_vendor/react-multi-carousel/lib/utils/next.js +13 -0
- package/_vendor/react-multi-carousel/lib/utils/previous.js +14 -0
- package/_vendor/react-multi-carousel/lib/utils/throttle.js +12 -0
- package/_vendor/react-multi-carousel/lib/utils/throwError.js +14 -0
- package/_virtual/Arrows.js +3 -0
- package/_virtual/Carousel.js +3 -0
- package/_virtual/CarouselItems.js +3 -0
- package/_virtual/Dots.js +3 -0
- package/_virtual/_commonjsHelpers.js +5 -0
- package/_virtual/clones.js +3 -0
- package/_virtual/common.js +3 -0
- package/_virtual/dots2.js +3 -0
- package/_virtual/elementWidth.js +3 -0
- package/_virtual/index.js +7 -0
- package/_virtual/index2.js +3 -0
- package/_virtual/index3.js +3 -0
- package/_virtual/mouseOrTouchMove.js +3 -0
- package/_virtual/next.js +3 -0
- package/_virtual/previous.js +3 -0
- package/_virtual/throttle.js +3 -0
- package/_virtual/throwError.js +3 -0
- package/_virtual/types.js +3 -0
- package/components/AntSwitch/index.js +6 -4
- package/components/Autocomplete/Autocomplete.js +19 -16
- package/components/Badge/index.js +8 -6
- package/components/BusySpinner/index.js +11 -8
- package/components/Button/Button.js +12 -9
- package/components/Checkbox.js +11 -8
- package/components/Confirm/index.js +14 -17
- package/components/DatePicker/DatePicker.js +19 -23
- package/components/DialogBox/DialogBox.js +25 -20
- package/components/Divisor.js +11 -8
- package/components/Dropdown.js +18 -15
- package/components/EditableTable/index.js +17 -14
- package/components/ErrorBox/ErrorBox.js +18 -15
- package/components/FileChooser/index.js +20 -15
- package/components/FormBottomBar/index.js +15 -12
- package/components/Icon/Icon.js +9 -6
- package/components/Icon/icons/index.js +252 -251
- package/components/IconTooltip/index.js +14 -9
- package/components/Map/MapBox.js +35 -32
- package/components/Map/MapContainer.js +10 -6
- package/components/Map/MapDateSliderControl.js +14 -12
- package/components/Map/MapDrawer.js +16 -12
- package/components/Map/MapLegend.js +32 -28
- package/components/Map/MapViewStyleControl.js +11 -9
- package/components/Map/ReactMapboxWrapper.js +1 -1
- package/components/Map/index.js +13 -11
- package/components/Map/types.js +5 -3
- package/components/Map/useMaintainLayerOrder.js +5 -2
- package/components/Markdown/index.js +6 -4
- package/components/Message/Message.js +25 -20
- package/components/MultiSelect/index.js +26 -23
- package/components/Navbar/NavFooter.js +8 -5
- package/components/Navbar/NavItem.js +14 -11
- package/components/Navbar/NavSection.js +10 -7
- package/components/Navbar/Navbar.js +16 -11
- package/components/Navbar/SubNavbar.js +8 -5
- package/components/Note.js +10 -7
- package/components/OverlayModal/OverlayModal.js +13 -11
- package/components/PageForm/index.js +15 -12
- package/components/PhotoChooser/index.js +30 -25
- package/components/PhotosCarousel/index.js +15 -18
- package/components/Pill/index.js +14 -11
- package/components/PillList/index.js +10 -7
- package/components/PlacementWrapper/index.js +8 -6
- package/components/PopoverMenu/Popover.js +12 -9
- package/components/PopoverMenu/index.js +14 -11
- package/components/PopoverMultiSelect/index.js +14 -11
- package/components/ProgressCircle/ProgressCircle.js +12 -9
- package/components/RadioButton.js +9 -6
- package/components/Select/Select.js +9 -6
- package/components/Select/SelectT.js +30 -26
- package/components/Separator/index.js +7 -5
- package/components/Size.js +1 -1
- package/components/Slider/index.js +9 -6
- package/components/SummaryBox.js +13 -10
- package/components/Tabs/index.js +22 -18
- package/components/TextTruncated/index.js +13 -20
- package/components/Textfield/Textfield.js +34 -28
- package/components/Textfield/TruncatedTextArea.js +12 -10
- package/components/TimelineSlider/TimelineMarker.js +8 -6
- package/components/TimelineSlider/TimelineRail.js +6 -4
- package/components/TimelineSlider/index.js +14 -12
- package/components/Tooltip/Tooltip.js +12 -7
- package/components/ViewPhotosDialog/index.js +14 -11
- package/components/VirtualWalkthrough/Annotation.js +10 -8
- package/components/VirtualWalkthrough/AnnotationEditPane.js +23 -21
- package/components/VirtualWalkthrough/AnnotationPanel.js +16 -14
- package/components/VirtualWalkthrough/Application.js +9 -7
- package/components/VirtualWalkthrough/AutoRotator.js +5 -3
- package/components/VirtualWalkthrough/BlockingSpinner.js +10 -7
- package/components/VirtualWalkthrough/BoundaryRing.js +8 -6
- package/components/VirtualWalkthrough/BoundaryWall.js +8 -6
- package/components/VirtualWalkthrough/CameraInfo.js +15 -13
- package/components/VirtualWalkthrough/ControlsInfoPane.js +59 -57
- package/components/VirtualWalkthrough/GradientSky.js +8 -6
- package/components/VirtualWalkthrough/SplatControls.js +37 -35
- package/components/VirtualWalkthrough/SplatCrop.js +6 -4
- package/components/VirtualWalkthrough/SplatFadeCrop.js +7 -5
- package/components/VirtualWalkthrough/SplatModel.js +17 -14
- package/components/VirtualWalkthrough/SplatRevealRain.js +6 -4
- package/components/VirtualWalkthrough/TfAnnotationManager.js +8 -5
- package/components/VirtualWalkthrough/TfXrNavigation.js +7 -5
- package/components/VirtualWalkthrough/VirtualWalkthroughViewer.js +47 -45
- package/components/VirtualWalkthrough/VrAnnotationPanel.js +9 -7
- package/components/VirtualWalkthrough/XrAnnotationInteraction.js +9 -7
- package/components/VirtualWalkthrough/XrExitButton.js +9 -7
- package/components/VirtualWalkthrough/XrGazeDwell.js +9 -7
- package/components/VirtualWalkthrough/XrPointerRay.js +9 -7
- package/components/VirtualWalkthrough/boundary-ring.js +7 -5
- package/components/VirtualWalkthrough/boundary-wall.js +8 -6
- package/components/VirtualWalkthrough/groundPlane.js +6 -3
- package/components/VirtualWalkthrough/gsplat-fade-crop-effect.js +5 -2
- package/components/VirtualWalkthrough/splatFormat.js +6 -4
- package/components/VirtualWalkthrough/vr-annotation-panel-layout.js +4 -2
- package/components/VirtualWalkthrough/vr-annotation-panel.js +8 -5
- package/components/VirtualWalkthrough/walkthrough-camera.js +6 -4
- package/components/VirtualWalkthrough/xr-annotation-candidates.js +8 -6
- package/components/VirtualWalkthrough/xr-annotation-interaction.js +9 -6
- package/components/VirtualWalkthrough/xr-annotation-targeting.js +5 -2
- package/components/VirtualWalkthrough/xr-button-arming.js +4 -2
- package/components/VirtualWalkthrough/xr-button-hold.js +5 -3
- package/components/VirtualWalkthrough/xr-exit-button.js +10 -8
- package/components/VirtualWalkthrough/xr-face-buttons.js +6 -4
- package/components/VirtualWalkthrough/xr-gaze-dwell-state.js +5 -3
- package/components/VirtualWalkthrough/xr-gaze-dwell.js +9 -7
- package/components/VirtualWalkthrough/xr-interactive-ui.js +10 -8
- package/components/VirtualWalkthrough/xr-pointer-ray.js +5 -3
- package/components/VirtualWalkthrough/xr-progress-pie.js +4 -2
- package/components/VirtualWalkthrough/xr-ray-quad.js +5 -2
- package/components/VirtualWalkthrough/xr-scene-bounds.js +5 -3
- package/components/VirtualWalkthrough/xr-teleport-gesture.js +4 -2
- package/components/svg/BlobbyGrayIconImage.js +13 -11
- package/components/svg/BlobbyGrayIconImport.js +13 -11
- package/components/svg/BlobbyGrayIconUploadToTheCloud.js +13 -11
- package/components/svg/BlobbyIconCloudChecked.js +41 -39
- package/components/svg/BlobbyIconExportOrUploadPhoto.js +41 -39
- package/components/svg/BlobbyIconFolder.js +41 -39
- package/components/svg/BlobbyIconGraphReport.js +41 -39
- package/components/svg/BlobbyIconHappy.js +41 -39
- package/components/svg/BlobbyIconHeartMonitor.js +41 -39
- package/components/svg/BlobbyIconLeaf.js +41 -39
- package/components/svg/BlobbyIconLibrary.js +41 -39
- package/components/svg/BlobbyIconNursery.js +41 -39
- package/components/svg/BlobbyIconOrganization.js +41 -39
- package/components/svg/BlobbyIconParchment.js +41 -39
- package/components/svg/BlobbyIconPeople.js +41 -39
- package/components/svg/BlobbyIconSeedBank.js +41 -39
- package/components/svg/BlobbyIconSeedling.js +41 -39
- package/components/svg/BlobbyIconSeeds.js +41 -39
- package/components/svg/BlobbyIconSite.js +42 -40
- package/components/svg/BlobbyIconSparkles.js +41 -39
- package/components/svg/BlobbyIconWrench.js +41 -39
- package/components/svg/Bug.js +8 -6
- package/components/svg/Calendar.js +8 -6
- package/components/svg/CaretDown.js +8 -6
- package/components/svg/CaretLeft.js +8 -6
- package/components/svg/CaretRight.js +8 -6
- package/components/svg/CaretUp.js +8 -6
- package/components/svg/ChevronDown.js +8 -6
- package/components/svg/ChevronUp.js +8 -6
- package/components/svg/Close.js +8 -6
- package/components/svg/Critical.js +8 -6
- package/components/svg/Edit.js +41 -39
- package/components/svg/Error.js +8 -6
- package/components/svg/Filter.js +8 -6
- package/components/svg/Folder.js +8 -6
- package/components/svg/Help.js +8 -6
- package/components/svg/Home.js +8 -6
- package/components/svg/IconAdd.js +8 -6
- package/components/svg/IconArrowRight.js +8 -6
- package/components/svg/IconBusinessNetwork.js +8 -6
- package/components/svg/IconCalendar.js +8 -6
- package/components/svg/IconCancel.js +8 -6
- package/components/svg/IconChargingBattery.js +8 -6
- package/components/svg/IconChecklist.js +8 -6
- package/components/svg/IconCheckmark.js +8 -6
- package/components/svg/IconCoinInHand.js +8 -6
- package/components/svg/IconColumns.js +8 -6
- package/components/svg/IconComment.js +8 -6
- package/components/svg/IconDashboard.js +8 -6
- package/components/svg/IconDataMigration.js +8 -6
- package/components/svg/IconDocument.js +8 -6
- package/components/svg/IconDownloadFromTheCloud.js +8 -6
- package/components/svg/IconEdit.js +8 -6
- package/components/svg/IconExpand.js +8 -6
- package/components/svg/IconExport.js +8 -6
- package/components/svg/IconExternalLink.js +8 -6
- package/components/svg/IconEye.js +8 -6
- package/components/svg/IconEyeOff.js +8 -6
- package/components/svg/IconFile.js +8 -6
- package/components/svg/IconFolder.js +8 -6
- package/components/svg/IconFullScreen.js +8 -6
- package/components/svg/IconFutures.js +8 -6
- package/components/svg/IconGraphReport.js +8 -6
- package/components/svg/IconHeartMonitor.js +8 -6
- package/components/svg/IconHelp.js +8 -6
- package/components/svg/IconHistory.js +8 -6
- package/components/svg/IconImport.js +8 -6
- package/components/svg/IconIndex.js +8 -6
- package/components/svg/IconLayers.js +8 -6
- package/components/svg/IconLibrary.js +8 -6
- package/components/svg/IconList.js +8 -6
- package/components/svg/IconLivePlant.js +8 -6
- package/components/svg/IconLocations.js +8 -6
- package/components/svg/IconMail.js +8 -6
- package/components/svg/IconManager.js +8 -6
- package/components/svg/IconMarker.js +8 -6
- package/components/svg/IconMenu.js +8 -6
- package/components/svg/IconMenuHorizontal.js +8 -6
- package/components/svg/IconModule.js +8 -6
- package/components/svg/IconMyLocation.js +8 -6
- package/components/svg/IconNote.js +8 -6
- package/components/svg/IconNursery.js +8 -6
- package/components/svg/IconOrg.js +8 -6
- package/components/svg/IconParchment.js +8 -6
- package/components/svg/IconPhoto.js +8 -6
- package/components/svg/IconPlantsFilled.js +8 -6
- package/components/svg/IconRedo.js +8 -6
- package/components/svg/IconRestorationSite.js +8 -6
- package/components/svg/IconSeedBank.js +8 -6
- package/components/svg/IconSeedling.js +8 -6
- package/components/svg/IconSettings.js +8 -6
- package/components/svg/IconSlice.js +8 -6
- package/components/svg/IconSubmit.js +8 -6
- package/components/svg/IconSubtract.js +8 -6
- package/components/svg/IconSynced.js +8 -6
- package/components/svg/IconTrashCan.js +8 -6
- package/components/svg/IconTreasureMap.js +8 -6
- package/components/svg/IconUnavailable.js +8 -6
- package/components/svg/IconUndo.js +8 -6
- package/components/svg/IconVariable.js +8 -6
- package/components/svg/IconVideo.js +9 -7
- package/components/svg/IconWifi.js +8 -6
- package/components/svg/Info.js +8 -6
- package/components/svg/Key.js +8 -6
- package/components/svg/Leaf.js +8 -6
- package/components/svg/Lock.js +8 -6
- package/components/svg/Logo.js +16 -14
- package/components/svg/MenuVertical.js +8 -6
- package/components/svg/Notification.js +8 -6
- package/components/svg/Person.js +8 -6
- package/components/svg/Plus.js +8 -6
- package/components/svg/RestorationSite.js +8 -6
- package/components/svg/Search.js +8 -6
- package/components/svg/Seeds.js +8 -6
- package/components/svg/Site.js +8 -6
- package/components/svg/Sparkles.js +8 -6
- package/components/svg/Species.js +8 -6
- package/components/svg/Species2.js +41 -39
- package/components/svg/Spinner.js +16 -14
- package/components/svg/Star.js +8 -6
- package/components/svg/Success.js +8 -6
- package/components/svg/SuccessFilled.js +8 -6
- package/components/svg/TerrawareLogoDesktop.js +17 -15
- package/components/svg/TerrawareLogoMobile.js +9 -7
- package/components/svg/Touchscreen.js +8 -6
- package/components/svg/UploadCloud.js +41 -39
- package/components/svg/Warning.js +8 -6
- package/components/svg/WelcomeClipboard.js +32 -30
- package/components/svg/index.js +127 -127
- package/components/table/EnhancedTableToolbar.js +18 -15
- package/components/table/EnhancedTableToolbarV2.js +8 -6
- package/components/table/TableCellRenderer.js +37 -32
- package/components/table/TableHeader.js +17 -14
- package/components/table/TableHeaderItem.js +18 -15
- package/components/table/density.js +5 -3
- package/components/table/index.js +40 -37
- package/components/table/sort.js +6 -4
- package/components/table/types.js +1 -1
- package/components/types/index.js +1 -1
- package/hooks/useBoolean.js +4 -2
- package/hooks/useCameraPosition.js +5 -2
- package/hooks/useDevicePerformance.js +6 -3
- package/hooks/useXr.js +6 -4
- package/index.js +55 -58
- package/package.json +6 -2
- package/style-dictionary-dist/TerrawareTheme.js +2 -1
- package/theme.js +5 -2
- package/utils/color.js +5 -2
- package/utils/date.js +7 -6
- package/utils/index.js +4 -5
- package/utils/preventDefaultEvent.js +2 -1
- package/utils/text.js +3 -2
- package/utils/useDeviceInfo.js +2 -1
- package/virtualWalkthrough.js +23 -31
- package/components/Button/button.test.js +0 -23
- package/components/MultiSelect/MultiSelect.test.js +0 -73
- package/components/VirtualWalkthrough/TfXrNavigation.test.js +0 -110
- package/components/VirtualWalkthrough/boundary-ring.test.js +0 -109
- package/components/VirtualWalkthrough/boundary-wall.test.js +0 -203
- package/components/VirtualWalkthrough/groundPlane.test.js +0 -45
- package/components/VirtualWalkthrough/splatFormat.test.js +0 -51
- package/components/VirtualWalkthrough/vr-annotation-panel-layout.test.js +0 -26
- package/components/VirtualWalkthrough/xr-annotation-targeting.test.js +0 -66
- package/components/VirtualWalkthrough/xr-button-arming.test.js +0 -35
- package/components/VirtualWalkthrough/xr-button-hold.test.js +0 -57
- package/components/VirtualWalkthrough/xr-exit-button.test.js +0 -23
- package/components/VirtualWalkthrough/xr-face-buttons.test.js +0 -82
- package/components/VirtualWalkthrough/xr-gaze-dwell-state.test.js +0 -61
- package/components/VirtualWalkthrough/xr-interactive-ui.test.js +0 -165
- package/components/VirtualWalkthrough/xr-progress-pie.test.js +0 -79
- package/components/VirtualWalkthrough/xr-ray-quad.test.js +0 -37
- package/components/VirtualWalkthrough/xr-scene-bounds.test.js +0 -70
- package/components/VirtualWalkthrough/xr-teleport-gesture.test.js +0 -90
- package/components/table/sort.test.js +0 -35
- package/utils/date.test.js +0 -84
- package/utils/text.test.js +0 -21
package/utils/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export { getDate, getDateDisplayValue, getTodaysDateFormatted, isInTheFuture, isWhitespaces, preventDefaultEvent, useDeviceInfo };
|
|
1
|
+
export { getDate, default as getDateDisplayValue, getTodaysDateFormatted, isInTheFuture } from './date.js';
|
|
2
|
+
export { default as preventDefaultEvent } from './preventDefaultEvent.js';
|
|
3
|
+
export { default as isWhitespaces } from './text.js';
|
|
4
|
+
export { default as useDeviceInfo } from './useDeviceInfo.js';
|
package/utils/text.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const isWhitespaces = str => str.match(/^\s+$/);
|
|
2
|
-
|
|
2
|
+
const titleCase = str => str.split(' ').map(word => {
|
|
3
3
|
if (word !== word.toUpperCase()) {
|
|
4
4
|
const lowerCaseWord = word.toLowerCase();
|
|
5
5
|
return lowerCaseWord.replace(lowerCaseWord.charAt(0), lowerCaseWord.charAt(0).toUpperCase());
|
|
@@ -7,4 +7,5 @@ export const titleCase = str => str.split(' ').map(word => {
|
|
|
7
7
|
return word;
|
|
8
8
|
}
|
|
9
9
|
}).join(' ');
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
export { isWhitespaces as default, titleCase };
|
package/utils/useDeviceInfo.js
CHANGED
package/virtualWalkthrough.js
CHANGED
|
@@ -1,31 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
import { TfXrNavigation } from './components/VirtualWalkthrough/TfXrNavigation';
|
|
25
|
-
import VirtualWalkthroughViewer from './components/VirtualWalkthrough/VirtualWalkthroughViewer';
|
|
26
|
-
import { BoundaryRingScript, boundaryRingMesh } from './components/VirtualWalkthrough/boundary-ring';
|
|
27
|
-
import { computeGroundPlane, yOnPlane } from './components/VirtualWalkthrough/groundPlane';
|
|
28
|
-
import { detectSplatFormat, splatLoaderFilename } from './components/VirtualWalkthrough/splatFormat';
|
|
29
|
-
import { WalkthroughCamera } from './components/VirtualWalkthrough/walkthrough-camera';
|
|
30
|
-
import { useDevicePerformance } from './hooks/useDevicePerformance';
|
|
31
|
-
export { Annotation, AnnotationEditPane, AnnotationPanel, Application, AutoRotator, BlockingSpinner, BoundaryRing, boundaryRingMesh, BoundaryRingScript, CameraInfo, computeGroundPlane, ControlsInfoPane, detectSplatFormat, GradientSky, SplatControls, SplatCrop, SplatFadeCrop, splatLoaderFilename, SplatModel, SplatRevealRain, TfAnnotationManager, TfXrNavigation, useDevicePerformance, VirtualWalkthroughViewer, WalkthroughCamera, yOnPlane };
|
|
1
|
+
export { default as Annotation } from './components/VirtualWalkthrough/Annotation.js';
|
|
2
|
+
export { default as AnnotationEditPane } from './components/VirtualWalkthrough/AnnotationEditPane.js';
|
|
3
|
+
export { default as AnnotationPanel } from './components/VirtualWalkthrough/AnnotationPanel.js';
|
|
4
|
+
export { default as Application } from './components/VirtualWalkthrough/Application.js';
|
|
5
|
+
export { AutoRotator } from './components/VirtualWalkthrough/AutoRotator.js';
|
|
6
|
+
export { default as BlockingSpinner } from './components/VirtualWalkthrough/BlockingSpinner.js';
|
|
7
|
+
export { default as BoundaryRing } from './components/VirtualWalkthrough/BoundaryRing.js';
|
|
8
|
+
export { default as CameraInfo } from './components/VirtualWalkthrough/CameraInfo.js';
|
|
9
|
+
export { default as ControlsInfoPane } from './components/VirtualWalkthrough/ControlsInfoPane.js';
|
|
10
|
+
export { default as GradientSky } from './components/VirtualWalkthrough/GradientSky.js';
|
|
11
|
+
export { default as SplatControls } from './components/VirtualWalkthrough/SplatControls.js';
|
|
12
|
+
export { default as SplatCrop } from './components/VirtualWalkthrough/SplatCrop.js';
|
|
13
|
+
export { default as SplatFadeCrop } from './components/VirtualWalkthrough/SplatFadeCrop.js';
|
|
14
|
+
export { default as SplatModel } from './components/VirtualWalkthrough/SplatModel.js';
|
|
15
|
+
export { default as SplatRevealRain } from './components/VirtualWalkthrough/SplatRevealRain.js';
|
|
16
|
+
export { TfAnnotationManager } from './components/VirtualWalkthrough/TfAnnotationManager.js';
|
|
17
|
+
export { TfXrNavigation } from './components/VirtualWalkthrough/TfXrNavigation.js';
|
|
18
|
+
export { default as VirtualWalkthroughViewer } from './components/VirtualWalkthrough/VirtualWalkthroughViewer.js';
|
|
19
|
+
export { BoundaryRingScript, boundaryRingMesh } from './components/VirtualWalkthrough/boundary-ring.js';
|
|
20
|
+
export { computeGroundPlane, yOnPlane } from './components/VirtualWalkthrough/groundPlane.js';
|
|
21
|
+
export { detectSplatFormat, splatLoaderFilename } from './components/VirtualWalkthrough/splatFormat.js';
|
|
22
|
+
export { WalkthroughCamera } from './components/VirtualWalkthrough/walkthrough-camera.js';
|
|
23
|
+
export { useDevicePerformance } from './hooks/useDevicePerformance.js';
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
-
import Button from './Button';
|
|
4
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
-
test('calls onClick prop when clicked', () => {
|
|
6
|
-
const handleClick = jest.fn();
|
|
7
|
-
render(/*#__PURE__*/_jsx(Button, {
|
|
8
|
-
onClick: handleClick,
|
|
9
|
-
label: "Click me"
|
|
10
|
-
}));
|
|
11
|
-
fireEvent.click(screen.getByText(/click me/i));
|
|
12
|
-
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
13
|
-
});
|
|
14
|
-
test('should not call onClick prop when button is disabled', () => {
|
|
15
|
-
const handleClick = jest.fn();
|
|
16
|
-
render(/*#__PURE__*/_jsx(Button, {
|
|
17
|
-
onClick: handleClick,
|
|
18
|
-
label: "Click me",
|
|
19
|
-
disabled: true
|
|
20
|
-
}));
|
|
21
|
-
fireEvent.click(screen.getByText(/click me/i));
|
|
22
|
-
expect(handleClick).toHaveBeenCalledTimes(0);
|
|
23
|
-
});
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
-
import MultiSelect from '.';
|
|
4
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
-
test('show options when placeholder is clicked', () => {
|
|
6
|
-
render(/*#__PURE__*/_jsx(MultiSelect, {
|
|
7
|
-
onAdd: () => undefined,
|
|
8
|
-
onRemove: () => undefined,
|
|
9
|
-
options: new Map([[1, 'foo'], [2, 'bar'], [3, 'baz']]),
|
|
10
|
-
valueRenderer: v => v,
|
|
11
|
-
selectedOptions: [],
|
|
12
|
-
placeHolder: "Select..."
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
// we should find the placeholder text
|
|
16
|
-
const placeHolder = screen.getByText('Select...');
|
|
17
|
-
expect(placeHolder).toBeInTheDocument();
|
|
18
|
-
|
|
19
|
-
// we should not find the options yet
|
|
20
|
-
expect(screen.queryByText('foo')).not.toBeInTheDocument();
|
|
21
|
-
expect(screen.queryByText('bar')).not.toBeInTheDocument();
|
|
22
|
-
expect(screen.queryByText('baz')).not.toBeInTheDocument();
|
|
23
|
-
|
|
24
|
-
// click the placeholder
|
|
25
|
-
fireEvent.click(placeHolder);
|
|
26
|
-
|
|
27
|
-
// now the options should be visible
|
|
28
|
-
expect(screen.queryByText('foo')).toBeInTheDocument();
|
|
29
|
-
expect(screen.queryByText('bar')).toBeInTheDocument();
|
|
30
|
-
expect(screen.queryByText('baz')).toBeInTheDocument();
|
|
31
|
-
});
|
|
32
|
-
test('clicking an option calls the onAdd handler', () => {
|
|
33
|
-
const handleAdd = jest.fn();
|
|
34
|
-
render(/*#__PURE__*/_jsx(MultiSelect, {
|
|
35
|
-
onAdd: handleAdd,
|
|
36
|
-
onRemove: () => undefined,
|
|
37
|
-
options: new Map([[1, 'foo'], [2, 'bar'], [3, 'baz']]),
|
|
38
|
-
valueRenderer: v => v,
|
|
39
|
-
selectedOptions: [],
|
|
40
|
-
placeHolder: "Select..."
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
|
-
// click the dropdown chevron
|
|
44
|
-
const dropdown = screen.getByLabelText('show-options');
|
|
45
|
-
fireEvent.click(dropdown);
|
|
46
|
-
|
|
47
|
-
// click one of the options
|
|
48
|
-
const option = screen.getByText('bar');
|
|
49
|
-
fireEvent.click(option);
|
|
50
|
-
|
|
51
|
-
// addHandler should have been called with id 2
|
|
52
|
-
expect(handleAdd).toBeCalledWith(2);
|
|
53
|
-
});
|
|
54
|
-
test('clicking the pill remove button calls the onRemove handler', () => {
|
|
55
|
-
const handleRemove = jest.fn();
|
|
56
|
-
render(/*#__PURE__*/_jsx(MultiSelect, {
|
|
57
|
-
onAdd: () => undefined,
|
|
58
|
-
onRemove: handleRemove,
|
|
59
|
-
options: new Map([[1, 'foo']]),
|
|
60
|
-
valueRenderer: v => v,
|
|
61
|
-
selectedOptions: [1]
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
// find a pill with the 'foo' text
|
|
65
|
-
expect(screen.queryByText('foo')).toBeInTheDocument();
|
|
66
|
-
|
|
67
|
-
// click the remove button
|
|
68
|
-
const removeButton = screen.getByLabelText('remove');
|
|
69
|
-
fireEvent.click(removeButton);
|
|
70
|
-
|
|
71
|
-
// handleRemove should have been called with id 1
|
|
72
|
-
expect(handleRemove).toBeCalledWith(1);
|
|
73
|
-
});
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { Vec3 } from 'playcanvas';
|
|
2
|
-
|
|
3
|
-
// The real base script is an .mjs file that Jest's default CRA transform config never transforms
|
|
4
|
-
// (node_modules is excluded), so importing it directly fails to parse. TfXrNavigation.postUpdate
|
|
5
|
-
// never calls into the base class, so a stub with no behaviour is enough to satisfy `extends`.
|
|
6
|
-
jest.mock('playcanvas/scripts/esm/xr/xr-navigation.mjs', () => ({
|
|
7
|
-
XrNavigation: class {}
|
|
8
|
-
}));
|
|
9
|
-
import { TfXrNavigation } from './TfXrNavigation';
|
|
10
|
-
const BOUNDS_CENTER = new Vec3(2, 0, 3);
|
|
11
|
-
const BOUNDS_RADIUS = 5;
|
|
12
|
-
const makeNavigation = options => {
|
|
13
|
-
const translate = jest.fn();
|
|
14
|
-
const navigation = Object.create(TfXrNavigation.prototype);
|
|
15
|
-
navigation.boundsCenter = BOUNDS_CENTER.clone();
|
|
16
|
-
navigation.boundsRadius = options.boundsRadius;
|
|
17
|
-
navigation.clampDistance = 0;
|
|
18
|
-
navigation.app = {
|
|
19
|
-
xr: {
|
|
20
|
-
active: options.xrActive
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
navigation.entity = {
|
|
24
|
-
translate
|
|
25
|
-
};
|
|
26
|
-
Object.assign(navigation, {
|
|
27
|
-
_cameraEntity: {
|
|
28
|
-
getPosition: () => options.head
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
return {
|
|
32
|
-
navigation,
|
|
33
|
-
translate
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
describe('TfXrNavigation.postUpdate', () => {
|
|
37
|
-
it('does not clamp when there is no active XR session, even with the head far outside the circle', () => {
|
|
38
|
-
const {
|
|
39
|
-
navigation,
|
|
40
|
-
translate
|
|
41
|
-
} = makeNavigation({
|
|
42
|
-
xrActive: false,
|
|
43
|
-
boundsRadius: BOUNDS_RADIUS,
|
|
44
|
-
head: new Vec3(1000, 1.5, 1000)
|
|
45
|
-
});
|
|
46
|
-
navigation.postUpdate();
|
|
47
|
-
expect(translate).not.toHaveBeenCalled();
|
|
48
|
-
expect(navigation.clampDistance).toBe(0);
|
|
49
|
-
});
|
|
50
|
-
it('does not clamp when boundsRadius is 0', () => {
|
|
51
|
-
const {
|
|
52
|
-
navigation,
|
|
53
|
-
translate
|
|
54
|
-
} = makeNavigation({
|
|
55
|
-
xrActive: true,
|
|
56
|
-
boundsRadius: 0,
|
|
57
|
-
head: new Vec3(1000, 1.5, 1000)
|
|
58
|
-
});
|
|
59
|
-
navigation.postUpdate();
|
|
60
|
-
expect(translate).not.toHaveBeenCalled();
|
|
61
|
-
expect(navigation.clampDistance).toBe(0);
|
|
62
|
-
});
|
|
63
|
-
it('does not clamp when the head is inside the circle', () => {
|
|
64
|
-
const {
|
|
65
|
-
navigation,
|
|
66
|
-
translate
|
|
67
|
-
} = makeNavigation({
|
|
68
|
-
xrActive: true,
|
|
69
|
-
boundsRadius: BOUNDS_RADIUS,
|
|
70
|
-
head: new Vec3(3, 1.5, 4)
|
|
71
|
-
});
|
|
72
|
-
navigation.postUpdate();
|
|
73
|
-
expect(translate).not.toHaveBeenCalled();
|
|
74
|
-
expect(navigation.clampDistance).toBe(0);
|
|
75
|
-
});
|
|
76
|
-
it('pulls the rig back and records the overshoot when the head is outside the circle in an active session', () => {
|
|
77
|
-
const {
|
|
78
|
-
navigation,
|
|
79
|
-
translate
|
|
80
|
-
} = makeNavigation({
|
|
81
|
-
xrActive: true,
|
|
82
|
-
boundsRadius: BOUNDS_RADIUS,
|
|
83
|
-
head: new Vec3(10, 1.5, 3)
|
|
84
|
-
});
|
|
85
|
-
navigation.postUpdate();
|
|
86
|
-
expect(translate).toHaveBeenCalledTimes(1);
|
|
87
|
-
expect(translate).toHaveBeenCalledWith(-3, 0, 0);
|
|
88
|
-
expect(navigation.clampDistance).toBe(3);
|
|
89
|
-
});
|
|
90
|
-
it('does not latch clampDistance across frames', () => {
|
|
91
|
-
const {
|
|
92
|
-
navigation,
|
|
93
|
-
translate
|
|
94
|
-
} = makeNavigation({
|
|
95
|
-
xrActive: true,
|
|
96
|
-
boundsRadius: BOUNDS_RADIUS,
|
|
97
|
-
head: new Vec3(10, 1.5, 3)
|
|
98
|
-
});
|
|
99
|
-
navigation.postUpdate();
|
|
100
|
-
expect(navigation.clampDistance).toBe(3);
|
|
101
|
-
Object.assign(navigation, {
|
|
102
|
-
_cameraEntity: {
|
|
103
|
-
getPosition: () => new Vec3(3, 1.5, 4)
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
navigation.postUpdate();
|
|
107
|
-
expect(translate).toHaveBeenCalledTimes(1);
|
|
108
|
-
expect(navigation.clampDistance).toBe(0);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { Vec3 } from 'playcanvas';
|
|
2
|
-
import { boundaryRingMesh } from './boundary-ring';
|
|
3
|
-
const FLAT = [new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(0, 0, 1)];
|
|
4
|
-
const toVertices = positions => {
|
|
5
|
-
const out = [];
|
|
6
|
-
for (let i = 0; i < positions.length; i += 3) {
|
|
7
|
-
out.push([positions[i], positions[i + 1], positions[i + 2]]);
|
|
8
|
-
}
|
|
9
|
-
return out;
|
|
10
|
-
};
|
|
11
|
-
describe('boundaryRingMesh', () => {
|
|
12
|
-
it('produces four vertices and six indices per dash', () => {
|
|
13
|
-
const geom = boundaryRingMesh({
|
|
14
|
-
center: new Vec3(0, 0, 0),
|
|
15
|
-
radius: 5,
|
|
16
|
-
width: 0.1,
|
|
17
|
-
groundPlane: FLAT,
|
|
18
|
-
dashCount: 16
|
|
19
|
-
});
|
|
20
|
-
expect(geom.positions).toHaveLength(16 * 4 * 3);
|
|
21
|
-
expect(geom.indices).toHaveLength(16 * 6);
|
|
22
|
-
});
|
|
23
|
-
it('places every vertex at the inner or outer radius from center in XZ', () => {
|
|
24
|
-
const center = new Vec3(2, 0, -3);
|
|
25
|
-
const radius = 4;
|
|
26
|
-
const width = 0.2;
|
|
27
|
-
const inner = radius - width / 2;
|
|
28
|
-
const outer = radius + width / 2;
|
|
29
|
-
const geom = boundaryRingMesh({
|
|
30
|
-
center,
|
|
31
|
-
radius,
|
|
32
|
-
width,
|
|
33
|
-
groundPlane: FLAT,
|
|
34
|
-
dashCount: 32
|
|
35
|
-
});
|
|
36
|
-
for (const [x,, z] of toVertices(geom.positions)) {
|
|
37
|
-
const d = Math.sqrt((x - center.x) ** 2 + (z - center.z) ** 2);
|
|
38
|
-
const atInner = Math.abs(d - inner) < 1e-6;
|
|
39
|
-
const atOuter = Math.abs(d - outer) < 1e-6;
|
|
40
|
-
expect(atInner || atOuter).toBe(true);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
it('lifts every vertex onto a tilted ground plane (y = z)', () => {
|
|
44
|
-
const tilted = [new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(0, 1, 1)];
|
|
45
|
-
const geom = boundaryRingMesh({
|
|
46
|
-
center: new Vec3(0, 0, 0),
|
|
47
|
-
radius: 3,
|
|
48
|
-
width: 0.1,
|
|
49
|
-
groundPlane: tilted,
|
|
50
|
-
dashCount: 8
|
|
51
|
-
});
|
|
52
|
-
for (const [, y, z] of toVertices(geom.positions)) {
|
|
53
|
-
expect(y).toBeCloseTo(z);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
it('references only in-range vertices from the index buffer', () => {
|
|
57
|
-
const geom = boundaryRingMesh({
|
|
58
|
-
center: new Vec3(0, 0, 0),
|
|
59
|
-
radius: 5,
|
|
60
|
-
width: 0.1,
|
|
61
|
-
groundPlane: FLAT,
|
|
62
|
-
dashCount: 8
|
|
63
|
-
});
|
|
64
|
-
const vertexCount = geom.positions.length / 3;
|
|
65
|
-
for (const idx of geom.indices) {
|
|
66
|
-
expect(idx).toBeGreaterThanOrEqual(0);
|
|
67
|
-
expect(idx).toBeLessThan(vertexCount);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
it('returns empty geometry for a non-positive radius', () => {
|
|
71
|
-
const geom = boundaryRingMesh({
|
|
72
|
-
center: new Vec3(0, 0, 0),
|
|
73
|
-
radius: 0,
|
|
74
|
-
width: 0.1,
|
|
75
|
-
groundPlane: FLAT
|
|
76
|
-
});
|
|
77
|
-
expect(geom.positions).toHaveLength(0);
|
|
78
|
-
expect(geom.indices).toHaveLength(0);
|
|
79
|
-
});
|
|
80
|
-
it('returns empty geometry for a non-positive width', () => {
|
|
81
|
-
const geom = boundaryRingMesh({
|
|
82
|
-
center: new Vec3(0, 0, 0),
|
|
83
|
-
radius: 5,
|
|
84
|
-
width: 0,
|
|
85
|
-
groundPlane: FLAT
|
|
86
|
-
});
|
|
87
|
-
expect(geom.positions).toHaveLength(0);
|
|
88
|
-
});
|
|
89
|
-
it('returns empty geometry for a non-positive dashCount', () => {
|
|
90
|
-
const geom = boundaryRingMesh({
|
|
91
|
-
center: new Vec3(0, 0, 0),
|
|
92
|
-
radius: 5,
|
|
93
|
-
width: 0.1,
|
|
94
|
-
groundPlane: FLAT,
|
|
95
|
-
dashCount: 0
|
|
96
|
-
});
|
|
97
|
-
expect(geom.positions).toHaveLength(0);
|
|
98
|
-
});
|
|
99
|
-
it('returns empty geometry for an invalid ground plane', () => {
|
|
100
|
-
const collinear = [new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(2, 0, 0)];
|
|
101
|
-
const geom = boundaryRingMesh({
|
|
102
|
-
center: new Vec3(0, 0, 0),
|
|
103
|
-
radius: 5,
|
|
104
|
-
width: 0.1,
|
|
105
|
-
groundPlane: collinear
|
|
106
|
-
});
|
|
107
|
-
expect(geom.positions).toHaveLength(0);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { Vec3 } from 'playcanvas';
|
|
2
|
-
import { boundaryWallMesh } from './boundary-wall';
|
|
3
|
-
const FLAT = [new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(0, 0, 1)];
|
|
4
|
-
const BASE = {
|
|
5
|
-
center: new Vec3(0, 0, 0),
|
|
6
|
-
radius: 5,
|
|
7
|
-
groundPlane: FLAT,
|
|
8
|
-
baseY: 0,
|
|
9
|
-
topY: 2.5,
|
|
10
|
-
gridSpacing: 0.5
|
|
11
|
-
};
|
|
12
|
-
const toVertices = positions => {
|
|
13
|
-
const out = [];
|
|
14
|
-
for (let i = 0; i < positions.length; i += 3) {
|
|
15
|
-
out.push([positions[i], positions[i + 1], positions[i + 2]]);
|
|
16
|
-
}
|
|
17
|
-
return out;
|
|
18
|
-
};
|
|
19
|
-
describe('boundaryWallMesh', () => {
|
|
20
|
-
it('produces four vertices, four UVs and six indices per segment', () => {
|
|
21
|
-
const geom = boundaryWallMesh({
|
|
22
|
-
...BASE,
|
|
23
|
-
segments: 16
|
|
24
|
-
});
|
|
25
|
-
expect(geom.positions).toHaveLength(16 * 4 * 3);
|
|
26
|
-
expect(geom.uvs).toHaveLength(16 * 4 * 2);
|
|
27
|
-
expect(geom.indices).toHaveLength(16 * 6);
|
|
28
|
-
});
|
|
29
|
-
it('places every vertex at the boundary radius in XZ', () => {
|
|
30
|
-
const center = new Vec3(2, 0, -3);
|
|
31
|
-
const geom = boundaryWallMesh({
|
|
32
|
-
...BASE,
|
|
33
|
-
center,
|
|
34
|
-
radius: 4,
|
|
35
|
-
segments: 32
|
|
36
|
-
});
|
|
37
|
-
for (const [x,, z] of toVertices(geom.positions)) {
|
|
38
|
-
expect(Math.sqrt((x - center.x) ** 2 + (z - center.z) ** 2)).toBeCloseTo(4);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
it('puts the top ring flat at topY for every column, even over tilted ground', () => {
|
|
42
|
-
// y = z, so the bottom sweeps -3..3 while the top has to stay pinned at 4.
|
|
43
|
-
const tilted = [new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(0, 1, 1)];
|
|
44
|
-
const geom = boundaryWallMesh({
|
|
45
|
-
...BASE,
|
|
46
|
-
groundPlane: tilted,
|
|
47
|
-
radius: 3,
|
|
48
|
-
topY: 4,
|
|
49
|
-
segments: 8
|
|
50
|
-
});
|
|
51
|
-
const verts = toVertices(geom.positions);
|
|
52
|
-
// Per segment the order is: bottom@a0, top@a0, bottom@a1, top@a1.
|
|
53
|
-
for (let i = 0; i < verts.length; i += 4) {
|
|
54
|
-
expect(verts[i + 1][1]).toBeCloseTo(4);
|
|
55
|
-
expect(verts[i + 3][1]).toBeCloseTo(4);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
it('sits the base on a tilted ground plane (y = z)', () => {
|
|
59
|
-
const tilted = [new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(0, 1, 1)];
|
|
60
|
-
const geom = boundaryWallMesh({
|
|
61
|
-
...BASE,
|
|
62
|
-
groundPlane: tilted,
|
|
63
|
-
radius: 3,
|
|
64
|
-
topY: 4,
|
|
65
|
-
segments: 8
|
|
66
|
-
});
|
|
67
|
-
const verts = toVertices(geom.positions);
|
|
68
|
-
for (let i = 0; i < verts.length; i += 4) {
|
|
69
|
-
expect(verts[i][1]).toBeCloseTo(verts[i][2]);
|
|
70
|
-
expect(verts[i + 2][1]).toBeCloseTo(verts[i + 2][2]);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
it('falls back to a flat base at baseY when no ground plane is supplied', () => {
|
|
74
|
-
const geom = boundaryWallMesh({
|
|
75
|
-
...BASE,
|
|
76
|
-
groundPlane: [],
|
|
77
|
-
baseY: 1.5,
|
|
78
|
-
topY: 3.5,
|
|
79
|
-
segments: 8
|
|
80
|
-
});
|
|
81
|
-
const verts = toVertices(geom.positions);
|
|
82
|
-
expect(verts).not.toHaveLength(0);
|
|
83
|
-
for (let i = 0; i < verts.length; i += 4) {
|
|
84
|
-
expect(verts[i][1]).toBeCloseTo(1.5);
|
|
85
|
-
expect(verts[i + 1][1]).toBeCloseTo(3.5);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
it('falls back to a flat base for a degenerate ground plane', () => {
|
|
89
|
-
const collinear = [new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(2, 0, 0)];
|
|
90
|
-
const geom = boundaryWallMesh({
|
|
91
|
-
...BASE,
|
|
92
|
-
groundPlane: collinear,
|
|
93
|
-
baseY: -2,
|
|
94
|
-
segments: 8
|
|
95
|
-
});
|
|
96
|
-
const verts = toVertices(geom.positions);
|
|
97
|
-
expect(verts).not.toHaveLength(0);
|
|
98
|
-
expect(verts[0][1]).toBeCloseTo(-2);
|
|
99
|
-
expect(verts[1][1]).toBeCloseTo(2.5);
|
|
100
|
-
});
|
|
101
|
-
it('reports whole-number grid cell counts derived from gridSpacing', () => {
|
|
102
|
-
// Circumference 2*pi*5 = 31.4159; at 0.5 m spacing that rounds to 63 columns.
|
|
103
|
-
// The ground is flat at y = 0, so rows = round((2.5 - 0) / 0.5) = 5.
|
|
104
|
-
const geom = boundaryWallMesh({
|
|
105
|
-
...BASE,
|
|
106
|
-
radius: 5,
|
|
107
|
-
topY: 2.5,
|
|
108
|
-
gridSpacing: 0.5,
|
|
109
|
-
segments: 8
|
|
110
|
-
});
|
|
111
|
-
expect(geom.columns).toBe(63);
|
|
112
|
-
expect(geom.rows).toBe(5);
|
|
113
|
-
});
|
|
114
|
-
it('derives rows from the average bottom, not from any single column', () => {
|
|
115
|
-
// Plane y = x - 1, sampled on a radius-3 circle at 6 columns (0, 60, 120, 180, 240, 300 deg):
|
|
116
|
-
// bottoms are 2, 0.5, -2.5, -4, -2.5, 0.5 -> average -1, which no column matches.
|
|
117
|
-
// rows = round((2.5 - -1) / 0.5) = round(7) = 7.
|
|
118
|
-
const tilted = [new Vec3(1, 0, 0), new Vec3(2, 1, 0), new Vec3(1, 0, 1)];
|
|
119
|
-
const geom = boundaryWallMesh({
|
|
120
|
-
...BASE,
|
|
121
|
-
groundPlane: tilted,
|
|
122
|
-
radius: 3,
|
|
123
|
-
topY: 2.5,
|
|
124
|
-
segments: 6
|
|
125
|
-
});
|
|
126
|
-
const bottoms = toVertices(geom.positions).filter((_, index) => index % 2 === 0).map(([, y]) => y);
|
|
127
|
-
expect(bottoms).toHaveLength(12);
|
|
128
|
-
for (const y of bottoms) {
|
|
129
|
-
expect(Math.abs(y + 1)).toBeGreaterThan(1);
|
|
130
|
-
}
|
|
131
|
-
expect(geom.rows).toBe(7);
|
|
132
|
-
});
|
|
133
|
-
it('emits u in cell units that wrap exactly at `columns`', () => {
|
|
134
|
-
const geom = boundaryWallMesh({
|
|
135
|
-
...BASE,
|
|
136
|
-
segments: 8
|
|
137
|
-
});
|
|
138
|
-
const us = [];
|
|
139
|
-
for (let i = 0; i < geom.uvs.length; i += 2) {
|
|
140
|
-
us.push(geom.uvs[i]);
|
|
141
|
-
}
|
|
142
|
-
expect(us[0]).toBeCloseTo(0);
|
|
143
|
-
// Last vertex of the last segment closes the loop at exactly `columns`.
|
|
144
|
-
expect(us[us.length - 1]).toBeCloseTo(geom.columns);
|
|
145
|
-
});
|
|
146
|
-
it('emits v as 0 at the base and `rows` at the top', () => {
|
|
147
|
-
const geom = boundaryWallMesh({
|
|
148
|
-
...BASE,
|
|
149
|
-
segments: 8
|
|
150
|
-
});
|
|
151
|
-
for (let i = 0; i < geom.uvs.length; i += 8) {
|
|
152
|
-
expect(geom.uvs[i + 1]).toBeCloseTo(0);
|
|
153
|
-
expect(geom.uvs[i + 3]).toBeCloseTo(geom.rows);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
it('references only in-range vertices from the index buffer', () => {
|
|
157
|
-
const geom = boundaryWallMesh({
|
|
158
|
-
...BASE,
|
|
159
|
-
segments: 8
|
|
160
|
-
});
|
|
161
|
-
const vertexCount = geom.positions.length / 3;
|
|
162
|
-
for (const idx of geom.indices) {
|
|
163
|
-
expect(idx).toBeGreaterThanOrEqual(0);
|
|
164
|
-
expect(idx).toBeLessThan(vertexCount);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
it('returns empty geometry for a non-positive radius', () => {
|
|
168
|
-
const geom = boundaryWallMesh({
|
|
169
|
-
...BASE,
|
|
170
|
-
radius: 0
|
|
171
|
-
});
|
|
172
|
-
expect(geom.positions).toHaveLength(0);
|
|
173
|
-
expect(geom.indices).toHaveLength(0);
|
|
174
|
-
});
|
|
175
|
-
it('returns empty geometry for a non-positive segment count', () => {
|
|
176
|
-
expect(boundaryWallMesh({
|
|
177
|
-
...BASE,
|
|
178
|
-
segments: 0
|
|
179
|
-
}).positions).toHaveLength(0);
|
|
180
|
-
});
|
|
181
|
-
it('returns empty geometry for a non-positive grid spacing', () => {
|
|
182
|
-
expect(boundaryWallMesh({
|
|
183
|
-
...BASE,
|
|
184
|
-
gridSpacing: 0
|
|
185
|
-
}).positions).toHaveLength(0);
|
|
186
|
-
});
|
|
187
|
-
it('returns empty geometry when topY is level with the base', () => {
|
|
188
|
-
expect(boundaryWallMesh({
|
|
189
|
-
...BASE,
|
|
190
|
-
topY: 0
|
|
191
|
-
}).positions).toHaveLength(0);
|
|
192
|
-
});
|
|
193
|
-
it('returns empty geometry when topY clears only part of a tilted base', () => {
|
|
194
|
-
// y = z on a radius-3 circle reaches 3, so a top at 2 is below the far half of the wall.
|
|
195
|
-
const tilted = [new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(0, 1, 1)];
|
|
196
|
-
expect(boundaryWallMesh({
|
|
197
|
-
...BASE,
|
|
198
|
-
groundPlane: tilted,
|
|
199
|
-
radius: 3,
|
|
200
|
-
topY: 2
|
|
201
|
-
}).positions).toHaveLength(0);
|
|
202
|
-
});
|
|
203
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Vec3 } from 'playcanvas';
|
|
2
|
-
import { computeGroundPlane, yOnPlane } from './groundPlane';
|
|
3
|
-
describe('computeGroundPlane', () => {
|
|
4
|
-
it('returns an up normal for a flat horizontal plane', () => {
|
|
5
|
-
const plane = computeGroundPlane([new Vec3(0, 5, 0), new Vec3(1, 5, 0), new Vec3(0, 5, 1)]);
|
|
6
|
-
expect(plane).not.toBeNull();
|
|
7
|
-
expect(plane.normal.x).toBeCloseTo(0);
|
|
8
|
-
expect(plane.normal.y).toBeCloseTo(1);
|
|
9
|
-
expect(plane.normal.z).toBeCloseTo(0);
|
|
10
|
-
expect(plane.point.y).toBeCloseTo(5);
|
|
11
|
-
});
|
|
12
|
-
it('flips a downward-facing normal so normal.y >= 0', () => {
|
|
13
|
-
const plane = computeGroundPlane([new Vec3(0, 0, 0), new Vec3(0, 0, 1), new Vec3(1, 0, 0)]);
|
|
14
|
-
expect(plane).not.toBeNull();
|
|
15
|
-
expect(plane.normal.y).toBeCloseTo(1);
|
|
16
|
-
});
|
|
17
|
-
it('computes a unit normal for a plane tilted 45deg about X (y = z)', () => {
|
|
18
|
-
const plane = computeGroundPlane([new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(0, 1, 1)]);
|
|
19
|
-
expect(plane).not.toBeNull();
|
|
20
|
-
const n = plane.normal;
|
|
21
|
-
expect(Math.sqrt(n.x * n.x + n.y * n.y + n.z * n.z)).toBeCloseTo(1);
|
|
22
|
-
expect(n.x).toBeCloseTo(0);
|
|
23
|
-
expect(n.y).toBeCloseTo(Math.SQRT1_2);
|
|
24
|
-
expect(n.z).toBeCloseTo(-Math.SQRT1_2);
|
|
25
|
-
});
|
|
26
|
-
it('returns null for fewer than 3 points', () => {
|
|
27
|
-
expect(computeGroundPlane([new Vec3(0, 0, 0), new Vec3(1, 0, 0)])).toBeNull();
|
|
28
|
-
});
|
|
29
|
-
it('returns null for collinear points', () => {
|
|
30
|
-
expect(computeGroundPlane([new Vec3(0, 0, 0), new Vec3(1, 0, 0), new Vec3(2, 0, 0)])).toBeNull();
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
describe('yOnPlane', () => {
|
|
34
|
-
it('returns the constant height on a flat plane', () => {
|
|
35
|
-
expect(yOnPlane(3, 7, new Vec3(0, 1, 0), new Vec3(0, 5, 0), -1)).toBeCloseTo(5);
|
|
36
|
-
});
|
|
37
|
-
it('interpolates height on a plane where y = z', () => {
|
|
38
|
-
const n = new Vec3(0, Math.SQRT1_2, -Math.SQRT1_2);
|
|
39
|
-
expect(yOnPlane(0, 2, n, new Vec3(0, 0, 0), 0)).toBeCloseTo(2);
|
|
40
|
-
expect(yOnPlane(10, -3, n, new Vec3(0, 0, 0), 0)).toBeCloseTo(-3);
|
|
41
|
-
});
|
|
42
|
-
it('returns the fallback when the normal is (near) horizontal', () => {
|
|
43
|
-
expect(yOnPlane(1, 1, new Vec3(1, 0, 0), new Vec3(0, 9, 0), 42)).toBe(42);
|
|
44
|
-
});
|
|
45
|
-
});
|