Constructing a rectangle from smaller rectangles - javascript
For the last few hours I've been attempting to construct a rectangle from smaller rectangles on any angle; I imagined doing so like this http://i.stack.imgur.com/Ymakk.png
[ Where the black lines represent the outline of the constructed rectangle and the red lines represent the triangles that construct it. The red rectangles have to be completely straight also. ]
Obviously it wouldn't look very defined unless I have a very small increment when trying to render it but the end product would hopefully look like a rectangle at a predetermined angle.
The screen is set up so that the top, left hand corner is (0, 0) and the bottom, right is (1, 1). How would I do this? Not specifically looking for actual code, pseudo-code or even an explanation, maybe some math.. would be brilliant! Thanks in advance.
Here's a bit of geometry for you:
If your rectangle is perfectly aligned, you can just draw one big rectangle and you win.
If it's slighted at any angle at all, you can express the lines as simple equations
y = m * x + c
where you insert x and y of both edges to calculate m and c (a very simple procedure actually), or you can calculate that m = tan(angle)
Then you can "just" walk down the y coordinates and get the corresponding x positions on the left and right lines that belong to the rectangle by inserting the y, c and m values to the equation and solving for x.
If you look at your rectangle picture, you can see that there's basically three parts: the first part goes from the bottom to the lower left edge. It follows the long side to the left and encounters an edge on the left side. After that you follow both short sides to the right and then you encounter the upper right edge and go up to the upper left corner (of course you could do this from the top down, too)
You'll need to carefully check if you've reached the edge between two lines on the left or right side and switch your values for m and c at the appropiate moments.
I think this should get you close to a solution
Related
How to rotate div in circular motion while counter rotating inner circles?
This image is what I am trying to achieve. Circles on the edges are clickable. Its structure is made such that each rotation will be multiple of 45 deg. I am using css transform rotate property for rotation. How is it supposed to work? When we click on any circle on the edge it should come to its active position and it should always rotate in clockwise direction. Here is what I did I achieved rotation by assigning numbers to the circles. i.e., if clicked on 7 number then it will rotate by angle (9-7)*45=90 degrees. (This time I did not change the numbers dynamically. i.e., as the circle is rotating the numbers given to the circles are the same.) This works fine here. But, lets see this scenario: when we click on 2nd position circle it will rotate by 315 deg and then if you click again on the same (second) position then it will make the angle of 270 and it rotates the div in anti-clockwise direction. I think this is its behavior. But, I don't want this to happen. It should rotate again in clockwise direction and should take the active position. Now to achieve above I did this: Adding angle with prev angle. var prev_degree = prev_degree + current_degree; (current degree is being calculated using the same formula from above.) This time I changed numbers dynamically i.e., on each click numbers are given to the desired positions. Starting 1 as from Active position till 8 as shown in Image But this time, when I rotate circle 1, 2 times it rotates perfect then it starts working strange. If you are constantly clicking on the same number then it will add the same angle and will keep rotating perfect no matter what your angle is. If you click on random circles then it wont work which is totally wrong. Why clockwise? Because the circles on edges, they contain icon of which I have to maintain position when whole circle rotates.(I can achieve that rotating circles on the edges by assigning negative angles. But, now this is not a problem.) There is no case when I am getting negative angle. Let me know if you are not clear with my question. Please let me know your suggestions to make this work :-)
Rotate a Two.js object in its position
I have a large circle with smaller ones inside made using two.js. My problem is that these two do not rotate in their own place but in the top left axis. I want the group of circles (circlesGroup) rotate only inside the large one in a static position. The circlesGroup and the large circle are grouped together as rotatoGroup. two.bind('update', function(frameCount, timeDelta) { circlesGroup.rotation = frameCount / 120; }); two.bind('update', function(frameCount, timeDelta) { rotatoGroup.rotation = frameCount / 60; }); The whole code is in CodePen.
All visible shapes when invoked with two.make... ( circles, rectangles, polygons, and lines ) are oriented in the center like this Adobe Illustrator example: When this shape's translation, rotation, or scale change those changes will be reflected as transformations about the center of the shape. Two.Groups however do not behave this way. Think of them as display-less rectangles. They're origin, i.e group.translation vector, always begins at (0, 0). In your case you can deal with this by normalizing the translation your defining on all your circles. Example 1: Predefined in normalized space In this codepen example we're defining the position of all the circles around -100, 100, effectively half the radius in both positive-and-negative x-and-y directions. Once we've defined the circles within these constraints we can move the whole group with group.translation.set to place it in the center of the screen. Now when the circles rotate they are perceived as rotating around themselves. Example 2: Normalizing after the fact In this codepen example we're working with what we already have. A Two.Group that contains all of our shapes ( the bigger circle as well as the array of the smaller circles ). By using the method group.center(); ( line 31 ) we can normalize the children of the group to be around (0, 0). We can then change the translation of the group in order to be in the desired position. N.B: This example is a bit complicated because it invokes underscore's defer method which forces the centering of the group after all the changes have been registered. I'm in the process of fixing this.
Show Extents Algorithm?
OH Great and Knowledgeable Stack Overflow, I humbly request your great minds assistance... I'm using the three js library, and I need to implement a 'show extents' button. It will move the camera to a position such that all the objects in the world are visible in the camera view (given they are not blocked of course). I can find the bounding box of all the objects in the world, say they are w0x,w0y,w0z and w1x,w1y,w1z How can I, given these to bounds, place the camera such that it will have a clear view of the edges of the box? Obviously there will have to be a 'side' chosen to view from...I've googled for an algorithm to no avail! Thanks!
So Let's say that you have picked a face. and that you are picking a camera position so that the camera's line-of-sight is parallel to one of the axes. Let's say that the face has a certain width, "w", and let's say that your camera has a horizontal field-of-view "a". What you want to figure out is what is the distance, "d" from the center of the face that the camera should be to see the whole width. If you draw it out you will see that you basically have an isosceles triangle whose base is length w and with the angle a at the apex. Not only that but the angle bisector of the apex angle forms two identical right triangles and it's length (to the base) is the distance we need to figure out. Trig tells us that the tangent of an angle is the ratio of the oposite and adjacent sides of the triangle. So tan(a/2) = (w/2) / d simplifying to: d = w / 2*tan(a/2) So if you are placing the camera some axis-aligned distance from one of your bounding box faces then you just need to move d distance along the axis of choice. Some caveats, make sure you are using radians for the javascript trig function input. Also you may have to compute this again for your face height and camera's vertical field-of-view and pick the farther distance if your face is not square. If you want to fit the bounding box from an arbitrary angle you can use the same ideas - but first you have to find the (aligned) bounding box of the scene projected onto a plane perpendicular to the camera's line of sight
Calculate new width when skewing in canvas
I'm using canvas for a project and I have a number of elements that I'm skewing. I'm only skewing on the y value and just want to know what the new width of the image is after skewing (so I can align it with another canvas element). Check out the code below to see what I mean ctx.save(); //skew the context ctx.transform(1,0,1.3,0,0,0); //draw two images with different heights/widths ctx.drawImage(image,0,0,42,60); ctx.drawImage(image,0,0,32,25); The goal would be to know that the 42 by 60 image was now a X by 60 image so I could do some translating before drawing it at 0,0. It's easy enough to measure each image individually, but I have different skew values and heights/widths throughout the project that need to be align. Currently I use this code (works decently for images between 25 and 42 widths): var skewModifier = imageWidth*(8/6)+(19/3); var skewAmount = 1.3; //this is dynamic in my app var width = (skewModifier*skewAmount)+imageWidth; As images get wider though this formula quickly falls apart (I think it's a sloping formula not a straight value like this one). Any ideas on what canvas does for skews?
You should be able to derive it mathematically. I believe: Math.atan(skewAmount) is the angle, in radians, that something is skewed with respect to the origin. So 1.3 would skew the object by 0.915 radians or 52 degrees. So here's a red unskewed object next to the same object skewed (painted green). So you have a right triangle: We know the origin angle (0.915 rads) and we know the adjacent side length, which is 60 and 25 for your two images. (red's height). The hypotenuse is the long side thats being skewed. And the opposite side is the triangle bottom - how much its been skewed! Tangent gets us opposite / adjacent if I recall, so for the first one: tan(0.915) = opposite / 60, solving for the opposite in JavaScript code we have: opposite = Math.tan(0.915)*60 So the bottom side of the skewed object starts about 77 pixels away from the origin. Lets check our work in the canvas: http://jsfiddle.net/LBzUt/ Looks good to me! The triangle in question of course is the canvas origin, that black dot I painted, and the bottom-left of the red rectangle, which is the original position that we're searching for before skewing. That was a bit of a haphazard explanation. Any questions?
Taking Simon's fiddle example one step further, so you can simply enter the degrees: Here's the fiddle http://jsfiddle.net/LBzUt/33/
Move rectangles so they don't overlap
This is a half programming, half math question. I've got some boxes, which are represented as four corner points. They are true rectangles, the intersections of two sets of parallel lines, with every line in each set at a right angle to both lines in the other set (just so we're clear.) For any set of n boxes, how can I efficiently calculate where to move them (the least distance) so that they do not overlap each other? I'm working in javascript here. Here's the data: //an array of indefinite length of boxes //boxes represented as arrays of four points //points represented as arrays of two things, an x and a y, measured in //pixels from the upper left corner var boxes = [[[504.36100124308336,110.58685958804978],[916.3610012430834,110.58685958804978],[916.3610012430834,149.58685958804978],[504.36100124308336,149.58685958804978]],[[504.4114378910622,312.3334473005064],[554.4114378910622,312.3334473005064],[554.4114378910622,396.3334473005064],[504.4114378910622,396.3334473005064]],[[479.4272869132357,343.82042608058134],[516.4272869132358,343.82042608058134],[516.4272869132358,427.82042608058134],[479.4272869132357,427.82042608058134]],[[345.0558946408693,400.12499171846],[632.0558946408694,400.12499171846],[632.0558946408694,439.12499171846],[345.0558946408693,439.12499171846]],[[164.54073131913765,374.02074227992966],[264.54073131913765,374.02074227992966],[264.54073131913765,428.02074227992966],[164.54073131913765,428.02074227992966]],[[89.76601656567325,257.7956256799442],[176.76601656567325,257.7956256799442],[176.76601656567325,311.7956256799442],[89.76601656567325,311.7956256799442]],[[60.711850703535845,103.10558195262593],[185.71185070353584,103.10558195262593],[185.71185070353584,157.10558195262593],[60.711850703535845,157.10558195262593]],[[169.5240557746245,23.743626531766495],[231.5240557746245,23.743626531766495],[231.5240557746245,92.7436265317665],[169.5240557746245,92.7436265317665]],[[241.6776988694169,24.30106373152889],[278.6776988694169,24.30106373152889],[278.6776988694169,63.30106373152889],[241.6776988694169,63.30106373152889]],[[272.7734457459479,15.53275710947554],[305.7734457459479,15.53275710947554],[305.7734457459479,54.53275710947554],[272.7734457459479,54.53275710947554]],[[304.2905062327675,-3.9599943474960035],[341.2905062327675,-3.9599943474960035],[341.2905062327675,50.04000565250399],[304.2905062327675,50.04000565250399]],[[334.86335590542114,12.526345270766143],[367.86335590542114,12.526345270766143],[367.86335590542114,51.52634527076614],[334.86335590542114,51.52634527076614]],[[504.36100124308336,110.58685958804978],[916.3610012430834,110.58685958804978],[916.3610012430834,149.58685958804978],[504.36100124308336,149.58685958804978]],[[504.4114378910622,312.3334473005064],[554.4114378910622,312.3334473005064],[554.4114378910622,396.3334473005064],[504.4114378910622,396.3334473005064]],[[479.4272869132357,343.82042608058134],[516.4272869132358,343.82042608058134],[516.4272869132358,427.82042608058134],[479.4272869132357,427.82042608058134]],[[345.0558946408693,400.12499171846],[632.0558946408694,400.12499171846],[632.0558946408694,439.12499171846],[345.0558946408693,439.12499171846]],[[164.54073131913765,374.02074227992966],[264.54073131913765,374.02074227992966],[264.54073131913765,428.02074227992966],[164.54073131913765,428.02074227992966]],[[89.76601656567325,257.7956256799442],[176.76601656567325,257.7956256799442],[176.76601656567325,311.7956256799442],[89.76601656567325,311.7956256799442]],[[60.711850703535845,103.10558195262593],[185.71185070353584,103.10558195262593],[185.71185070353584,157.10558195262593],[60.711850703535845,157.10558195262593]],[[169.5240557746245,23.743626531766495],[231.5240557746245,23.743626531766495],[231.5240557746245,92.7436265317665],[169.5240557746245,92.7436265317665]],[[241.6776988694169,24.30106373152889],[278.6776988694169,24.30106373152889],[278.6776988694169,63.30106373152889],[241.6776988694169,63.30106373152889]],[[272.7734457459479,15.53275710947554],[305.7734457459479,15.53275710947554],[305.7734457459479,54.53275710947554],[272.7734457459479,54.53275710947554]],[[304.2905062327675,-3.9599943474960035],[341.2905062327675,-3.9599943474960035],[341.2905062327675,50.04000565250399],[304.2905062327675,50.04000565250399]],[[334.86335590542114,12.526345270766143],[367.86335590542114,12.526345270766143],[367.86335590542114,51.52634527076614],[334.86335590542114,51.52634527076614]]] This fiddle shows the boxes drawn on a canvas semi-transparently for clarity.
You could use a greedy algorithm. It will be far from optimal, but may be "good enough". Here is a sketch: 1 Sort the rectangles by the x-axis, topmost first. (n log n) 2 for each rectangle r1, top to bottom //check for intersections with the rectangles below it. // you only have to check the first few b/c they are sorted 3 for every other rectangle r2 that might intersect with it 4 if r1 and r2 intersect //this part is easy, see #Jose's answer 5 left = the amount needed to resolve the collision by moving r2 left 6 right = the amount needed to resolve the collision by moving r2 right 7 down = the amount needed to resolve the collision by moving r2 down 8 move r2 according to the minimum value of (left, right down) // (this may create new collisions, they will be resolved in later steps) 9 end if 10 end 11 end Note step 8 could create a new collision with a prior rectangle, which wouldn't be resolved properly. Hm. You may need to carry around some metadata about previous rectangles to avoid this. Thinking...
Keep in mind the box model, given any two rectangles you have to calculate the two boxes width and height, adding their respective margins, paddings, and borders (add the left/right of them to detect collision on the x axis, and top/bottom to detect collision on the y axis), then you can calculate the distance between element 1 and 2 adding the result to their respective coordinate position, for example ((positionX2+totalWidth2) - (positionX1+totalWidth1)) to calculate collision along the X axis. If it is negative, they are overlapping. Once you know this, if they won't overlap by moving them, you can move them normally, otherwise you have to subtract the amount of space they are overlapping from the value you want to move them. Since the environment is a 2D plane, this should be pretty straightforward. With a library such as jQuery would be a joke, but even in plain js is just basic addiction and subtraction.
Assuming the boxes are aligned to the x and y axis as in your comment, first I'd change the representation of each rectangle to 4 points: top, right, bottom, left and store them as points on the rectangle. Second, let's simplify the problem to "Given n rectangles, where is the nearest point where rectangle r can move to so that it doesn't overlap any other rectangles"? That simplifies the problem a great deal, but also should provide a decent solution. Thus, we have our function: function deOverlapTheHonkOuttaTheRectangle(rectangle, otherRectangles){ .. } Now, each other rectangle will disallow a certain range of motion for the original rectangle. Thus, you calculate all of these disallowed moves. From these, you can calculate the disallow shape that overlaps the origin and each other. For example, lets say rect1 disallows a shift of -3px to 5px right and 4px to 10px up, and rect2 disallows -4px to 1px right and -2px to 5px up. rect1 was not considered until rect2 came along, since that one overlaps the origin and rect1. Starting with rect2, you'd have [[-4, -2],[1,-2],[1,5],[-4,5]]. Figuring in rect1 gives [[-4, -2],[1,-2],[1,4],[5,4],[5,10],[-3,10],[-3,5],[-4,5]] (see image below for clarification). You keep building these up for each overlapping disallowed rectangle. Once you have considered all the rectangles, then you can use a distance formula from the origin to get the smallest distance you can move your rectangle and move it. Finally, you repeat this process for all remaining rectangles.