Polygon with multiple paths -- how to connect? - javascript

I am creating a polygon with multiple event handlers -- I can click-drag to draw freehand, hold shift and click to snap to roads, and do a normal click as well. Originally, I had one array that I pushed each of these points to. However, since the event handlers are unique, debugging an array that I pass everywhere and modify everywhere seems like bad form.
I've made it so that the polygon paths is an array of arrays of points. When I shift-click, it makes an array of points, when I click-drag, it makes an array of points, and then I push these to the array of arrays.
However, how do I connect these together? I am currently not able to connect the endpoints of one array to the start of the next. Because I'm trying to modularize my code, I don't want to have to pass the last point of an array to the event listener that makes the next array, because that defeats the purpose of having separate arrays.
The documentation is pretty thin on multiple paths for a polygon.
Here's what I have so far.
http://jsfiddle.net/skitterm/fn4g5/1/
Pseudocode:
array C = new Array();
addEventListener for click {
populate array A
C.push(A);
}
addEventListener for shift-click {
populate array B
C.push(B);
}
addEventListener for right-click {
create polygon {
paths: C
}
}
I can create a polygon by just shift-clicking, or by clicking, or clicking and dragging, but I can't make a polygon where one side is done by shift-clicking and the rest by normal clicks.
Any ideas?

Related

trying to store array values for an 'undo' function in p5js

I've made a sort of drawing application in p5js - I have a multidimensional array called points which consists of shapes, which have x,y coordinates for the points of shapes. So:
shapes[0][0] = [10,10]
shapes[1][3] = [47,98]
etc.
I have a mousePressed function. At the time the mouse is pressed, before the points of these shapes are manipulated, I want to store the original shapes array as undoArr.
Then, as the user drags the mouse, the coordinates in the shapes array are updated. If the user then decides to undo, I have a function keyPressed that I want to be able to populate shapes array with the values from undoArr.
But no matter what I try - it seems that the undo array and the shapes array always have the same values, which is strange because, if I log the state of a coordinate in the shapes array:
function mousePressed() {
if (!isMousePressed){
undoArr = [...shapes]; //define undoArr as the current shapes array
console.log(shapes[0][0]); //outputs 10,41 (for example)
and then log the state on mouseReleased:
function handleMouseReleased(){
console.log(shapes[0][0]); //outputs 69,122 (for example)
I can verify that they have different values at start and finish. And I can verify from the logs that mousePressed is not accidentally being triggered somehow when it shouldn't, and the same for mouseReleased.
P5js has a draw function, which is constantly repositioning the points of the shapes array based on where the user drags them with their mouse. And in that draw function, I can place a log statement and verify that it fires after mousePressed and before mouseReleased.
However, if I try to store the values of the shapes array on mousePressed, undoArr = [...shapes] and then on keyPressed try to populate the shapes array with the contents of the undoArr, it does nothing - because somehow undoArr always contains the same data as shapes.
Am I copying the array improperly? I've tried instead of the spread undoArr = shapes.slice() but that also didn't work. I've even tried emptying the array first, but nothing seems to work.
A complete gist of the file is available here.
I think what you need here is a deep clone of your multidimensional array. It seems like you are just copying references instead of values.
The spread operator ([...]) does not do a deep clone, so the objects it copies will contain references.
Lodash has a great cloneDeep function: https://lodash.com/docs/4.17.11#cloneDeep
or you could write one of your own.

THREE.JS Multiple groups containing the same objects

I'm currently learning THREE.js and trying to make a playable rubik's cube.
I want to be able to rotate a face as a whole instead of moving every single cube one at a time, and I can do so by creating a THREE.Group and adding the cubes in it. The problem is that a single cube is contained in multiple faces, and I can't find a solution. If I create an object, add it to a first group, then add it to a second group, it is removed from the first group.
I'm pretty sure there is a workaround but can't find it as I'm really new to THREE.js and 3D programming (I only followed a basic course https://www.udemy.com/3d-programming-with-javascript-and-the-threejs-3d-library/).
There is my code but I don't think it will be very usefull anyway.
https://pastebin.com/Hq66UvBU
Thanks
Welcome to Stack Overflow. Please remember to edit your question to include your code, because when the pastebin link dies, your question loses important context.
The correct way to add an object to a THREE.Group is through the add function, like you do. But an object added to multiple groups will only ever be a child of the last group to which it was added. This is because add looks to see if the object already has a defined parent, and removes the object from that parent before setting the new parent (r97 code).
Example:
let obj = new THREE.Object3D()
let p1 = new THREE.Group()
let p2 = new THREE.Group()
p1.add(obj) // obj.parent == p1
p2.add(obj) // 1. three.js calls p1.remove(obj) 2. obj.parent == p2
Beyond this reason, and as #Mugen87 mentioned, your cubes need to not only be able to have multiple memberships, but also to be able to enter and leave face groups as their positions change. To me this says you will almost need to transform the cubes individually. You could use a THREE.Group to make it easier to conceptualize, but there would be extra overhead to actually implement it that way.
Maybe a late answer but try to work in another way and group the cubes that need to turn the moment the turn function is activated and then turn the group around, then empty the group.

How to apply transformation to selection in Illustrator by scripting

I managed to select every thing I want in Illustrator with a ExtendScript Toolkit javascript code: lots of things (text, path, symbols, ...) in several layers. Now I want to resize them the same way, then move them.
I know how to apply a transformation to one object by code, but I want to avoid looping on each element because it would be very very long and transformation would be applied from the anchor point of each element, so my drawings wouldn't be cohesive.
So, I am looking for a way to do like in Illustrator UI: right click > transform > scale. Is there any UI command like this I could access from code (javascript)?
There are at least three ways to do this:
Record AI Actions that perform required transformations, and then play these Actions (by DoScript) from your script
Group selected objects and apply required transformations to the group as #Dane proposed. You need to backup the Layer object property to allow objects to be restored in original layers, as shown in VBA example below:
For i = Index_Lo To Index_Hi
Call Layers_Backup.Add(Item:=SelectedItems(i).Layer, Key:=Format(i))
Call SelectedItems(i).Move(Temp_Group, AiElementPlacement.aiPlaceAtEnd)
Next i
Call Temp_Group.Resize(scaleX:=120, scaleY:=120, changeLineWidths:=120)
For i = Index_Lo To Index_Hi
Call SelectedItems(i).Move(Layers_Backup(Format(i)), AiElementPlacement.aiPlaceAtEnd)
Next i
Call Windows API functions (like PostMessage (..., WM_COMMAND, ..., ...), SendDlgItemMessage, FindWindowEx etc) to show, fill and execute required AI transformations dialog boxes
IMHO, item #1 is the easiest to implement while item#2 is the most reliable
So I dont know if you can get away with not looping in some form or other. that said, if you dont mind putting your selection in to a group, it might be faster to loop through your selection adding to a group which might be faster than looping and through the selection and scale and moving each element. With the group object you can then do groupObject.scale() and .translate().
Here is a snippet i took from a script of mine.
#target "illustrator"
var aiApp = app.activeDocument;
var aSelection = aiApp.selection;
var aGroup = app.activeDocument.groupItems.add();
for (i=0; i < aSelection.length; i++){
aSelection[i].move( aGroup, ElementPlacement.INSIDE);
aSelection[i].move( aGroup, ElementPlacement.PLACEATEND);
}
//moves up 700 points and scales by 200
aGroup.translate(0,700)
aGroup.resize(200, 200, true , true, true, true, 200)

InDesign extendScript: How do I transform the entire selection?

By using the simple array app.selection[x], you can apply a transformation to any object in the selection, independently. But how do I apply a transformation to the entire selection together?
For example: inside InDesign, I can select two side-by-side objects and flip them horizontally, causing them to switch places and flip.
Inside a script, I can target each object in the selection, but they will not switch places; they will remain in the same place and flip.
for ( var x = 0; x < app.selection.length; x++ ){
app.selection[x].absoluteFlip = Flip.HORIZONTAL;
}
I could possibly group the selection, apply a transformation, then ungroup when finished, but this seems like unnecessary bulk that could slow down the code. I can easily do it manually inside InDesign, so it should follow that there's some way to access app.selection as a single object instead of an array. Does such an object exist?
Not really a solution, but it's worth noting that I don't think absoluteFlip is the action being performed, but a state indicating if the item has ben flipped. It's writable so you can set the state, but I think what's happening when using the menu to flip is flipItem: http://jongware.mit.edu/idcs6js/pc_PageItem.html#flipItem,
in which you can set "around" coordinates.
Now getting the origin of the selection box isn't straightforward for some reason (or maybe it is but I don't know how), but you can either use first object coordinates to set the origin so you can flip it around different coordinates depending on order of selection. Or you can sort the array to find left most coordinates (or whichever is needed), like this:
var selection_array = app.selection;
selection_array.sort(function(a, b){return a.visibleBounds[1]-b.visibleBounds[1]})
var flip_origin = [selection_array[0].visibleBounds[1],selection_array[0].visibleBounds[0]]
for(i=0;i<app.selection.length;i++){
app.selection[i].flipItem(Flip.HORIZONTAL, flip_origin);
}
Not sure it's easier or faster than grouping and ungrouping though.
Consider resize. It has a "individual/global" parameter :
void resize (in: varies, from: varies, by: ResizeMethods, values: Array of varies[, resizeIndividually: bool=true][, consideringRulerUnits: bool=false])
Resize the page item.

How to draw multiple polylines by clicking?

I was looking for a solution but all are how to draw polylines from the json file etc. Main question is how to get the functionality to create a new polyline and store old in array each time when click on button "New Polyline"? Second how to leave polylines and draw new on map after click "New Polyline" button and clean and restore only when click right button? May better way is to store Polylines outside the class, or make a new separately class for this? May you have to approach this differently?
Bad demo but highlight what I mean I hope: jsfiddle
Array was moved to global scope but can't setMap on last polyline works only via clearOverlays function. Now complications arise on other buttons. I create additional global object newPoly but don't know whether is good idea may better get object from myPolyline? In other side restore case can't set on map stored in array polylines.
To save the polylines you've made, create another global variable to store the polylines and push them in, and at the same time, setMap(null) on the last polyline in the array. You can't store the polylines you've made in the same object, since you're making a new one each time.
So move:
this.polyLines = [];
out of the class, and into the global scope, or into another class, its fine to leave the marker array in there, since that's local to that polyline instance.
this should also help - https://developers.google.com/maps/documentation/javascript/overlays#OverlaysOverview

Categories

Resources