PointCloud Component render issue fetch() custom data [react-three-fiber] - arrays

Based on a snippet of original r3f-example found in PointCloud.js
Tested by myself, this above original component is able to render pointcloud by pushing individual x y z value into the for-loop in Particle() function.
I modified it and added a `fetch()' method to retrieve a custom data txt file, snippet as shown below,
...
export function Particles() {
const [positions, colors] = useMemo(() => {
let positions = [], colors = []
positions.length = 3
colors.length = 3
const HEADER_SIZE = 4;
let stream, longArray, len;
let clusterCount ;
let xy_size ;
let clusterSize = [];
let XY_arr = [];
fetch(map)
.then((r) => r.text())
.then(text => {
stream = text.toString().split("\n"); // split by next line
longArray = stream.slice(2,); // remove header from main longArray
len = longArray.length;
for (let i = 0, count = 0; i < len; i += HEADER_SIZE ) {
xy_size = longArray.slice((i + HEADER_SIZE - 1), (i + HEADER_SIZE));
XY_arr.push(longArray.slice((i + HEADER_SIZE ), (i + HEADER_SIZE + xy_size*2)));
console.log(" Points in PointCloud " + count + ": " + xy_size );
clusterSize.push(xy_size);
clusterCount = count;
i += xy_size*2;
count ++;
}
for (let i = 0; i < (clusterCount-2); i++) {
for (let j = 0; j < clusterSize[i]*2; j+=2) {
positions.push( XY_arr[i][j] )
positions.push(0)
positions.push( XY_arr[i][j+1] )
colors.push(1)
colors.push(0.5)
colors.push(0.5)
console.log( XY_arr[i][j] );
}
}
}
)
return [new Float32Array(positions), new Float32Array(colors)]
}, [])
...
...
, map is the custom text file in string, with single data line-by-line
The fetch() method is able to read a custom pointcloud file into XY_arr as an object of Array(). I have checked that XY_arr[i][j] in the nested-forloop are able to return correct x and z value in console.
Current problem is that no pointcloud being rendered onto <Canvas />
Is the problem caused by position.push() nested loop being inside of 'fetch()' method ? And how to resolve. Thank you.

better use const [state, set] = useState() and then fetch in useEffect calling "set" when you're done. putting an async fetch request inside useMemo is practically a side-effect in the render function - which isn't good, nor will it work like that.

Related

how to shuffle an array except for the item in the middle?

Iยดm creating a Bingo board and I need that the one in the middle always stays the same even when shuffleing this array:
const bbb = [
"๐Ÿ˜‹",
"๐Ÿ˜",
"๐Ÿคฃ",
"๐Ÿ˜ƒ",
"๐Ÿ˜„",
"๐Ÿ˜…",
"๐Ÿ˜†",
"๐Ÿ˜‰",
"๐Ÿ˜Š",
"๐Ÿ˜Š",
"๐Ÿ˜Ž ",
"๐Ÿคฉ",
"๐ŸŽฏ",
"๐Ÿ˜ถ",
"๐Ÿ˜ซ",
"๐Ÿ˜ด",
"๐Ÿค ",
"๐Ÿ™„ ",
"๐Ÿ˜‘",
"๐Ÿ˜ฏ",
"๐Ÿ˜š",
"๐Ÿ˜ฅ",
"๐Ÿ˜ฎ ",
"๐Ÿ˜›",
"๐Ÿ˜"
];
const data = arrayShuffle(bbb).reduce(
(data, value, index) => ({ ...data, [index]: value }),
{}
);
and then Im maping the array to display the Tiles and create the board like this:
{Object.keys(data).map(id => (
<Tile
key={id}
id={id}
isSet={state.checked[id]}
onToggle={() => toggle(id)}
>
{data[id]}
</Tile>
))}
Remove the middle item from the array initially. Then do the in-place randomizing of items and finally attach the middle item to the array.
This runs in O(n) time complexity where n is the size of your array and you always get a uniform random permutation.
const bbb = [ "๐Ÿ˜‹", "๐Ÿ˜", "๐Ÿคฃ", "๐Ÿ˜ƒ", "๐Ÿ˜„", "๐Ÿ˜…", "๐Ÿ˜†", "๐Ÿ˜‰", "๐Ÿ˜Š", "๐Ÿ˜Š", "๐Ÿ˜Ž", "๐Ÿคฉ", "๐ŸŽฏ", "๐Ÿ˜ถ", "๐Ÿ˜ซ", "๐Ÿ˜ด", "๐Ÿค", "๐Ÿ™„", "๐Ÿ˜‘", "๐Ÿ˜ฏ", "๐Ÿ˜š", "๐Ÿ˜ฅ", "๐Ÿ˜ฎ", "๐Ÿ˜›", "๐Ÿ˜", ];
const getRandomInt = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
};
const arrayShuffleInplaceExceptMiddle = (A) => {
const middle = A.splice(A.length/2, 1);
const n = A.length;
const middleIndex = Math.floor(n / 2);
for (let i = 0; i < n; i++) {
let swapIndex = getRandomInt(i, n);
let a = A[i];
A[i] = A[swapIndex];
A[swapIndex] = a;
}
A.splice(n/2, 0, ...middle)
};
// test runs
Array.from({length: 10}, () => {
arrayShuffleInplaceExceptMiddle(bbb);
console.log(bbb.join(""));
})
Just shuffle the array normally, but remove the the value before the shuffle and insert it back afterward:
/**
* Durstenfeld shuffle
*
* - https://stackoverflow.com/a/12646864/438273
* - https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
*
* #param {unknown[]} array
*/
function shuffleArray (array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
/**
* Like a normal shuffle, but for a bingo board
*
* #param {unknown[]} array
*/
function bingoShuffle (array) {
const index = Math.floor((array.length - 1) / 2);
const [value] = array.splice(index, 1);
shuffleArray(array);
array.splice(index, 0, value);
}
// Let's keep the board small for this demo:
const board = [
"๐Ÿ˜Š",
"๐Ÿ˜Š",
"๐Ÿ˜Ž",
"๐Ÿคฉ",
"๐ŸŽฏ",
"๐Ÿ˜ถ",
"๐Ÿ˜ซ",
"๐Ÿ˜ด",
"๐Ÿค",
];
console.log(board.join(' '));
// Shuffle it a few times and look at the results:
for (let i = 0; i < 10; i += 1) {
bingoShuffle(board);
console.log(board.join(' '));
}
And because you tagged this with reactjs, I'm guessing this is (immutable) state, so you'll need to get a new array when shuffling, like this:
const updatedBoard = bingoShuffle([...board]);
// ^^^^^^^^^^
// Shallow copy into new array so you don't mutate React state

Output variables one by one from array

how do I pull variables from array one by one? I want to make a card with one saying Zlin, second Praha, etc... The way it works now is that it outputs all of them at once 4x. Thank you.
const KartyLoop = () => {
var mesta = ['Zlin','Praha','Ostrava','Brno']
var lokace = []
for (var i=0; i < mesta.length; i++)
{
lokace += mesta + "\n"
}
return (<Text>{lokace}</Text>);
}
Your code pushes the array itself and not its values.
If I understand correctly you want to copy an array.
You would want to do this.
const KartyLoop = () => {
var mesta = ['Zlin','Praha','Ostrava','Brno']
var lokace = []
for (var i=0; i < mesta.length; i++)
{
lokace += mesta[i] + "\n"
}
return (lokace);
}

Not able to change state properties of redux reducer in function call

I have this redux reducer case, which has multiple conditions to work with. I am getting issue in changing value of state properties.
//code explaination:
In the second condition I am checking if action.hoverIndex > action.dragIndex, and if the condition is true then it creates "td" variable to hold the new state. After state change I have to make some changes in the properties of the state.
In the else part of the 2nd condition when I change the properties of "td" by assigning new value in for loop, it works as expected, but same thing when I try in "nestedConditionHandler" it does not work. not sure what is causing this issue.
const cmdArray = [
"ECommand",
"BCommand",
"CCommand",
"DCommand",
];
const cmdPair = {
ECommand: "EndE",
BCommand: "EndB",
CCommand: "EndC",
DCommand: "EndD",
};
const notFirstCommand = [
"PCommand",
"QCommand",
"XCommand"
];
case actionTypes.UPDATE_COMMAND_WORKFLOW:
// Deep clone of current state
const temp = cloneDeep(state);
// Draged command state
const dragCard = temp[action.dragIndex];
const tempDragCard = cloneDeep(dragCard);
// hovered command state
const hoverCard = temp[action.hoverIndex];
const tempHoverCard = cloneDeep(hoverCard);
//condition one
if (
action.hoverIndex === 0 &&
notFirstCommand.includes(dragCard.class_name)
) {
return temp;
}
//condition 2
// command drag from top to bottom
if (action.hoverIndex > action.dragIndex) {
const td = update(temp, {
$splice: [
[action.dragIndex, 1],
[action.hoverIndex, 0, tempDragCard],
],
});
let startIndex;
let endconditionIndex;
// for nested commands
const nestedConditionHandler = (i, currState) => {
startIndex = i + 1;
endconditionIndex = td.indexOf(
td.find((cur) => cmdPair[currState.class_name] === cur.class_name)
);
while (startIndex < endconditionIndex) {
const tempTd = td[startIndex];
console.log(tempTd);
console.log(currState.indent + 1);
td[startIndex].indent = currState.indent +1
td[startIndex].parentId = currState.parentId
if (cmdArray.includes(td[startIndex].class_name)) {
nestedConditionHandler(startIndex, td[startIndex]);
}
startIndex += 1;
}
};
if (
dragCard.class_name === "ECommand" ||
dragCard.class_name === "EfCommand"
) {
for (let i = action.dragIndex; i < action.hoverIndex; i++) {
td[i].indent = dragCard.indent + 1;
td[i].parentId = dragCard.parentId;
}
} else {
for (let i = action.dragIndex; i < action.hoverIndex; i++) {
td[i].indent = dragCard.indent;
td[i].parentId = dragCard.parentId;
if (cmdArray.includes(td[i].class_name)) {
nestedConditionHandler(i, td[i]);
}
}
}
return td;
}
// command drag from bottom to top , next condition

Why my array getting appended instead of clearing and Adding new data

I am trying to achieve a method in which the array steps got filled with new data every time I click on the button of Create New array, but instead of that, the data is getting appended instead of updating.
here are my states :
const [arr , setArray] = useState(createArray())
const [steps , setSteps] = useState([]);
const [selectedAlgorithm , setSelectedAlgorithm] = useState ();
here is my create new Array function :
const handleCreateNewData = ()=>{
let newarr = createArray();
setArray ([]);
setArray([...newarr]);
setSteps ([]);
setTimeout(()=>{
if ( algorithms[selectedAlgorithm] !== undefined){
algorithms[selectedAlgorithm](arr, steps , setSteps);
console.log('running')
}
},2000)
}
here is my bubble sort algorithm :
export const BubbleSort = (array , steps ,setSteps) =>{
let funarray = new Array();
funarray = [...array] ;
for (let i = 0 ; i < funarray.length-1 ; i++){
for(let j = 0 ; j < funarray.length-1 ; j++){
if(funarray[j]>funarray[j+1]){
[funarray[j],funarray[j+1]] = [funarray[j+1],funarray[j]]
setSteps([...steps, funarray])
steps.push(funarray.slice());
console.log('Working')
}
}
}
return funarray;
}
What is supposed to do is every time I click on create new array it should generate a new set of arrays but instead of creating new arrays it just appending the new arrays in the old steps.
You can create a temp array to hold the steps, then when the loops are done, call setSteps:
const BubbleSort = (array, steps, setSteps) => {
let funarray = [];
funarray = [...array];
let temp = [];
for (let i = 0; i < funarray.length - 1; i++) {
for (let j = 0; j < funarray.length - 1; j++) {
if (funarray[j] > funarray[j + 1]) {
[funarray[j], funarray[j + 1]] = [funarray[j + 1], funarray[j]];
temp.push(funarray)
}
}
}
setSteps(temp);
return funarray;
};
Sample: https://codesandbox.io/s/cool-wind-ijj7z?file=/src/App.js

How to convert JSON to URL params string as per my expected value?

I am working on an angular project. For a method getting a response JSON to convert stringify and POST a body to an API is done. Now the problem is for another one function I should send this value as a URL parameter I tried some ways but didn't get expected result. Please find the below codes and help me out. Thanks
Here is my JSON format value
const bodyJSON = [{FullPackageIDs:[11,7],
PartialPkg:[
{PackageID:4,
FormsList:[
{Form_Name:"Form name One"},
{Form_Name:"Form name Two"}]},
{PackageID:6,
FormsList:[
{Form_Name:"Form name Three"},
{Form_Name:"Form name Four"},
{Form_Name:"Form name Five"}
]
}
]
}]
My expected URL string value like below
http://localhost:4200/DownloadPackage?FullPackageIDs[0]=11&FullPackageIDs[1]=7&PartialPkg[0].PackageID=4&PartialPkg[0].FormsList[0].Form_Name=Form name One&PartialPkg[0].FormsList[1].Form_Name=Form name Two&PartialPkg[1].PackageID=6&PartialPkg[0].FormsList[0].Form_Name=Form name Three&PartialPkg[1].FormsList[1].Form_Name=Form name Four&PartialPkg[2].FormsList[2].Form_Name=Form name Five
I tried via forloop but didnt get expected result. Here is the code for what I tried.
for (let i = 0; i < getSelectedId.length; i++) {
fullPackageParams = `${fullPackageParams}FullPackageIDs[${i}]=${getSelectedId[i]}&`;
for (let j = 0; j < getPartialId.length; j++) {
// const getPartialName = this.partialPackage.map(res => res[i].FormsList);
const getPartialName = getPartialId[j].FormsList;
partialPackageIDParams = `${partialPackageIDParams}PartialPkg[${j}].PackageID=${getPartialId[j].PackageID}&`;
for (let index = 0; index < getPartialName.length; index++) {
partialPackageNameParams = `PartialPkg[${index}].FormsList[${index}].Form_Name=${getPartialName[index].Form_Name}&`;
}
}
}
console.log('params for full packages', fullPackageParams + partialPackageIDParams + partialPackageNameParams);
even if it seems kinda strange to me that you need to pass all of those params using query, you can try this
it just uses ES6 map, reduce functions to create your query string
let URLQuery = bodyJSON.map(value => {
const packageIDs = value.FullPackageIDs.map((v, i) => `FullPackageIDs[${i}]=${encodeURIComponent(v)}`);
const partialPkgs = value.PartialPkg.map((v, i) => {
const startKey = `PartialPkg[${i}]`;
return [
`${startKey}.PackageID=${v.PackageID}`
].concat(
v.FormsList.map((v, i) => `${startKey}.FormsList[${i}].Form_Name=${encodeURIComponent(v.Form_Name)}`)
);
}).reduce((arr, v) => {
return arr.concat(v)
}, []);
return packageIDs.concat(partialPkgs);
}).reduce((arr, v) => {
return arr.concat(v);
}, []).join("&");
const fullURL = `https://example.com?${URLQuery}`;

Resources