I have a list of lat long coordinates each with corresponding azimuths (directions) such as:
Site | Cell | Lat | Long | Azimuth (degrees) | Beamwidth
CE0001 | CE0001U09A1 | X | Y | 0 | 65
CE0001 | CE0001U09B1 | X | Y | 120 | 65
CE0001 | CE0001U09C1 | X | Y | 240 | 65
For each unique cell, I would like to create a triangular polygon that is oriented in the direction of the azimuth for the corresponding cell with a width of 65degs and a radius of say 2km. I would like to generate shapes similar to what is shown below.
Can anyone point me in the direction as to how I could begin coding this up to loop through each entry in my file and how to generate a single google earth file that contains a polygon for each one? There are approx 9000 or so cells that require a polygon but if I can get this working for a small sample I would be very happy.
Here is and old post I made to a forum of a script to build hexagon tiles. Some of the calls are to the GIS API but I think you can probably extracted the needed VBA code:
.. VB script to create some hexagon tiles.
It creates tiles of a given radius (circle around a tile), not side length. If you want side length you will need to do the math and updte the code.
Here is the Comments from the .map file:
Creating a drawing of hexagon tiles:
R - radius
Radius of circumscribed circle around tile
a - Apothem:
Distance from centroid perpendicular to a side
a = R * cos(1/2 * 360/n) (n=6 for a hexagon
A set of hexagon tiles would be a series of six sided
"circles" centered on two point grids (1 & 2). Both grids
would have the spacing of:
in X --- 3R
in Y --- 2a
Grid 2 would be offset from grid 1 by:
in X ---- 3R/2
in Y ---- 2a/2
To test script delete all objects in A then
run the script.
This sample was only tested with a lat/long drawing. I'm not
sure of all the ramifications of using a projected drawing.
To use with your data set the start point (upper left) in the script and desired radius.
Set precision and run Normailize Topology when done to join
the tiles.
Code was based on the FreeStuff sample scripts ScriptRandomPoints
and ScriptSpatialOperations.
Please post any problems you find with this code.
Hmmm.. the attachments option is gone? :-?
Send me your address via email and send the .map file if you'd like.
Here's the code:
Sub Main
' test lat/long drawing
' ** ** delete all objects in A to test
set drawing = Application.ActiveDocument.ComponentSet("A")
set objects = drawing.ObjectSet
sides = 6
pi = 3.14159
R = 2.5 ' radius in degrees
interiorAngle = (360/6) * (pi / 180) ' in radians
a = abs(R * cos(0.5 * interiorAngle)) ' apothem
' pick/make a start point - upper left
Set startPoint = Application.NewPoint
startPoint.X = -25
startPoint.Y = 73.6602540378444
' grid (4x3x2)
for i = 0 to 3
for j = 0 to 2
' -- create point grid 1
Set point = Application.NewPoint
point.X = startPoint.X + (i * 3 * R)
point.Y = startPoint.Y - (j * 2 * a)
' objects.Add Application.NewGeom(GeomPoint, point) ' centroid
Set pointSet = Application.NewPointSet
For k = 0 To sides -1
Set pt = Application.NewPoint
' calculate angle
angle = (k*2*Pi/sides)' - (360/sides)/2
' obtain point on circle
pt.X = point.X + R*Cos(angle)
pt.Y = point.Y + R*Sin(angle)
pointSet.Add(pt)
Next
objects.Add Application.NewGeom(GeomArea, pointSet)
' -- create point grid 2
Set point = Application.NewPoint
point.X = startPoint.X + (i * 3 * R) + ((3 * R)/2)
point.Y = startPoint.Y - (j * 2 * a) - a
' objects.Add Application.NewGeom(GeomPoint, point) ' centroid
Set pointSet = Application.NewPointSet
For k = 0 To sides -1
Set pt = Application.NewPoint
' calculate angle
angle = (k*2*Pi/sides)' - (360/sides)/2
' obtain point on circle
pt.X = point.X + R*Cos(angle)
pt.Y = point.Y + R*Sin(angle)
pointSet.Add(pt)
Next
objects.Add Application.NewGeom(GeomArea, pointSet)
next
next
msgbox "Done!"
End Sub
Here's a cleaned up version that just developes one hex tile. You should be able to modify it to do what you want.
Sub xx()
Dim startPoint As clsPoint
Dim Point As clsPoint
Dim pt As clsPoint
Dim pts As Collection
Dim s As String
' lat/long (western hemisphere?)
Dim sides, i, j, k As Integer
Dim Pi, R, interiorAngle, A, Angle As Double
sides = 6
Pi = 3.14159
R = 0.25 ' radius in degrees
interiorAngle = (360 / 6) * (Pi / 180) ' in radians
A = Abs(R * Cos(0.5 * interiorAngle)) ' apothem
' pick/make a start point - upper left
Set startPoint = New clsPoint
startPoint.X = -121.5
startPoint.Y = 35.5
s = "Longitude" & vbTab & "Latitude" & vbCrLf
s = s & startPoint.X & vbTab & startPoint.Y & vbCrLf
Set Point = New clsPoint
Point.X = startPoint.X '+ (i * 3 * R)
Point.Y = startPoint.Y '- (j * 2 * A)
Set pts = New Collection
For k = 0 To sides - 1
Set pt = New clsPoint
' calculate angle
Angle = (k * 2 * Pi / sides) ' - (360/sides)/2
' Debug.Print Angle
' obtain point on circle
pt.X = Point.X + R * Cos(Angle)
pt.Y = Point.Y + R * Sin(Angle)
pts.Add pt
Next
For Each pt In pts
s = s & pt.X & vbTab & pt.Y & vbCrLf
Next
Debug.Print s
Stop
End Sub
clsPoint just contains:
Public X As Double
Public Y As Double
Related
I just wrote this code to perform an iterative calculation. It finds the X,Y coordinates where an unknown parabola is tangent to a known circle. It is based on other iterative functions I've written that have worked flawlessly. I'm stumped as to what the issue is. Here is the code:
Public Function Jext(PA As Double, Xcl As Double, Ycl As Double, Ctr As Double, Rnl As Double, Finl As Double) As Double
Pi = 3.14159265358979
tol = 0.00000001
Dim x(20) As Double
Dim Yc(20) As Double
Dim Yp(20) As Double
Dim A(20) As Double
Dim Diff(20) As Double
Dim It As Integer
Dim hF As Double
Dim Sf As Double
'Xcl is the horizontal position of the root radius center line
'Ycl is the vertical position of the root radius center line
'Ctr is root radius. It's an approximation of the trochoid and is typically the cutter tip radius
'Rnl is the radius to the point where the load line intersects the tooth centerline. It is the apex of the parabola
'x is the horizontal position that is common to the parabola and circle. It is the independent variable
'Yc is the vertical position on the circle at point x
'Yp is the vertical position on the parabola at point x
'A is the leading term of the parabolic equation
'Diff is the calculated difference in vertical positions of circle and parabola
'Set initial guess values. x(0) is 5% of the radius (left edge of circle) and x(1) is 95% of the radius(bottom of the circle)
x(0) = (Xcl - Ctr) + 0.05 * Ctr
x(1) = (Xcl - Ctr) + 0.95 * Ctr
Yc(0) = Ycl - (Ctr ^ 2 - (x(0) - Xcl) ^ 2) ^ 0.5
Yc(1) = Ycl - (Ctr ^ 2 - (x(1) - Xcl) ^ 2) ^ 0.5
A(0) = Tan(WorksheetFunction.Acos((Xcl - x(0)) / Ctr) + Pi / 2) / (2 * x(0))
A(1) = Tan(WorksheetFunction.Acos((Xcl - x(1)) / Ctr) + Pi / 2) / (2 * x(1))
Yp(0) = A(0) * x(0) ^ 2 + Rnl
Yp(1) = A(1) * x(1) ^ 2 + Rnl
Diff(0) = Yp(0) - Yc(0)
Diff(1) = Yp(1) - Yc(1)
For It = 1 To 19 Step 1
x(It + 1) = x(It) - (Diff(It) - 0) * (x(It - 1) - x(It)) / (Diff(It - 1) - Diff(It))
Yc(It + 1) = Ycl - (Ctr ^ 2 - (x(It + 1) - Xcl) ^ 2) ^ 0.5
A(It + 1) = Tan(WorksheetFunction.Acos((Xcl - x(It + 1)) / Ctr) + Pi / 2) / (2 * x(It + 1))
Yp(It + 1) = A(It + 1) * x(It + 1) ^ 2 + Rnl
Diff(It + 1) = Yp(It + 1) - Yc(It + 1)
If Abs(Diff(It + 1)) < tol Then Exit For
Debug.Print Diff(It + 1)
Next It
hF = Rnl - Yp(t + 1)
Sf = 2 * x(t + 1)
Jext = 1 / (Cos(Finl) / Cos(PA) * (6 * hF / Sf ^ 2 - Tan(Finl) / Sf))
End Function
I put a stop at the "Next It" line to check the values as it went through the iterative loops. When I execute the code, all of the values are as expected and the value of Abs(Diff(It+1)) is not small enough to exit the for loop in the IF statement. I put the Debug.Print statement in there to make sure it was getting that far in the code and it did print Diff(It+1). So it executes everything to that point. Then when I continue the function it just stops and returns a #VALUE error in the spreadsheet. I've no idea why it won't continue the for loop. Anyone see something I've missed?
I'm trying to make a label move from one cell to another. I figured out the position offsets and created 3 "tweens" as animators call them. But when I run the code, the Label doesn't display until the sub has ended. If I comment out the last position the label is in the right spot. How do I make Excel update the screen to show the label before I move it again?
xo and yo are integers either -1, 0, or 1. playerLocation is a range, might as well be ActiveCell.
Sub moveAnimation()
Dim moveAnim As OLEObject
Set moveAnim = Worksheets(currentSheet).OLEObjects(currentSheet & "player")
moveAnim.Left = playerLocation.Left - 0.5 + yo * (playerLocation.Width / 4)
moveAnim.Top = playerLocation.Top + 0.25 + xo * (playerLocation.Width / 4)
Sleep (25)
moveAnim.Left = playerLocation.Left - 0.5 + yo * (playerLocation.Width / 2)
moveAnim.Top = playerLocation.Top + 0.25 + xo * (playerLocation.Width / 2)
Sleep (25)
moveAnim.Left = playerLocation.Left - 0.5 + yo * 3 * (playerLocation.Width / 4)
moveAnim.Top = playerLocation.Top + 0.25 + xo * 3 * (playerLocation.Width / 4)
Sleep (25)
moveAnim.Left = 0
moveAnim.Top = 0
I've figured it out. ActiveSheet.Calculate will force an update so i put it between each position
I know the following:
P (x,y coordinates).
A1 and A2 (angles in degrees)
R (radius of circle).
Now I need to calculate a center for the green circle, as to make it 'tangentize?' the two blue lines (it will later be minkowski'ed with other shapes to form a point of a rounded triangle).
Any help will be appreciated!
My code for the depicted example:
//KNOWNS
P=[-3.0,1.0,0.0];
A1=60; A2=-5;
R=5;
//UNKNOWN
SECRET_CALCULATION = [8.2,4.3,0];//???
//ILLUSTRATION
C0=[0,0,0,1]; C1=[0,1,1,0.3]; C2=[0,1,0,0.4]; C3=[1,0,0,0.4];//Colors
translate(P){
color(C1) rotate(A1) translate([0,-0.5,0]) square([250,1],0);
color(C1) rotate(A2) translate([0,-0.5,0]) square([250,1],0);
color(C2) translate(SECRET_CALCULATION) circle(R);
}
//EXPLANATIONS
color(C0) translate(P) {
translate(SECRET_CALCULATION){
translate([0,-0.2,0]) square([R,0.4],0);
translate([R+1,0,0]) rotate(-90) text(str("R:",R),halign="center",valign="top",0.75);
translate([0,0.2,0]) text("[x?,y?,0]",halign="center",valign="bottom",0.75);
}
rotate(((A1-A2)/2)-90) translate([0,-1,0]) text(str("P: ",P),halign="center",valign="top",0.75);
rotate(A1) text(str(" A1: ",A1,"°"),halign="left",valign="center",0.75);
rotate(A2) text(str(" A2: ",A2,"°"),halign="left",valign="center",0.75);
}
Center of circle lies at the bisector of rays A1 and A2. So we can find direction for this bisector as
B = (A1 + A2) / 2 = 27.5 here
(but don't forget about angle normalization - angle -5 might be represented as 355 and so on)
And angle between bisector and A1 or A2 is
D = (A1 - A2) / 2 = 32.5 here
We can see that points C(enter)-T(angentpoint)-P form right triangle with relation
L (P-C, DistAlongBisector) = R / Sin(D)
So we can find center coordinates as
C.X = P.X + Cos(B) * L
C.Y = P.Y + Sin(B) * L
Quick hand-check gives
L=5/Sin(32.5)=9.3
C.X = -3 + Cos(27.5)*9.3 = 5.24
C.Y = 1 + Sin(27.5)*9.3 = 5.3
I'm working with Corona and Lua script.
basically I want to scale and rotate a 'larger than screen' image with dual-touch
Please help :)
Try this
-- one more thing
-- turn on multitouch
system.activate("multitouch")
-- which environment are we running on?
local isDevice = (system.getInfo("environment") == "device")
-- returns the distance between points a and b
function lengthOf( a, b )
local width, height = b.x-a.x, b.y-a.y
return (width*width + height*height)^0.5
end
-- returns the degrees between (0,0) and pt
-- note: 0 degrees is 'east'
function angleOfPoint( pt )
local x, y = pt.x, pt.y
local radian = math.atan2(y,x)
local angle = radian*180/math.pi
if angle < 0 then angle = 360 + angle end
return angle
end
-- returns the degrees between two points
-- note: 0 degrees is 'east'
function angleBetweenPoints( a, b )
local x, y = b.x - a.x, b.y - a.y
return angleOfPoint( { x=x, y=y } )
end
-- returns the smallest angle between the two angles
-- ie: the difference between the two angles via the shortest distance
function smallestAngleDiff( target, source )
local a = target - source
if (a > 180) then
a = a - 360
elseif (a < -180) then
a = a + 360
end
return a
end
-- rotates a point around the (0,0) point by degrees
-- returns new point object
function rotatePoint( point, degrees )
local x, y = point.x, point.y
local theta = math.rad( degrees )
local pt = {
x = x * math.cos(theta) - y * math.sin(theta),
y = x * math.sin(theta) + y * math.cos(theta)
}
return pt
end
-- rotates point around the centre by degrees
-- rounds the returned coordinates using math.round() if round == true
-- returns new coordinates object
function rotateAboutPoint( point, centre, degrees, round )
local pt = { x=point.x - centre.x, y=point.y - centre.y }
pt = rotatePoint( pt, degrees )
pt.x, pt.y = pt.x + centre.x, pt.y + centre.y
if (round) then
pt.x = math.round(pt.x)
pt.y = math.round(pt.y)
end
return pt
end
-- calculates the average centre of a list of points
local function calcAvgCentre( points )
local x, y = 0, 0
for i=1, #points do
local pt = points[i]
x = x + pt.x
y = y + pt.y
end
return { x = x / #points, y = y / #points }
end
-- calculate each tracking dot's distance and angle from the midpoint
local function updateTracking( centre, points )
for i=1, #points do
local point = points[i]
point.prevAngle = point.angle
point.prevDistance = point.distance
point.angle = angleBetweenPoints( centre, point )
point.distance = lengthOf( centre, point )
end
end
-- calculates rotation amount based on the average change in tracking point rotation
local function calcAverageRotation( points )
local total = 0
for i=1, #points do
local point = points[i]
total = total + smallestAngleDiff( point.angle, point.prevAngle )
end
return total / #points
end
-- calculates scaling amount based on the average change in tracking point distances
local function calcAverageScaling( points )
local total = 0
for i=1, #points do
local point = points[i]
total = total + point.distance / point.prevDistance
end
return total / #points
end
-- creates an object to be moved
function newTrackDot(e)
-- create a user interface object
local circle = display.newCircle( e.x, e.y, 50 )
-- make it less imposing
circle.alpha = .5
-- keep reference to the rectangle
local rect = e.target
-- standard multi-touch event listener
function circle:touch(e)
-- get the object which received the touch event
local target = circle
-- store the parent object in the event
e.parent = rect
-- handle each phase of the touch event life cycle...
if (e.phase == "began") then
-- tell corona that following touches come to this display object
display.getCurrentStage():setFocus(target, e.id)
-- remember that this object has the focus
target.hasFocus = true
-- indicate the event was handled
return true
elseif (target.hasFocus) then
-- this object is handling touches
if (e.phase == "moved") then
-- move the display object with the touch (or whatever)
target.x, target.y = e.x, e.y
else -- "ended" and "cancelled" phases
-- stop being responsible for touches
display.getCurrentStage():setFocus(target, nil)
-- remember this object no longer has the focus
target.hasFocus = false
end
-- send the event parameter to the rect object
rect:touch(e)
-- indicate that we handled the touch and not to propagate it
return true
end
-- if the target is not responsible for this touch event return false
return false
end
-- listen for touches starting on the touch layer
circle:addEventListener("touch")
-- listen for a tap when running in the simulator
function circle:tap(e)
if (e.numTaps == 2) then
-- set the parent
e.parent = rect
-- call touch to remove the tracking dot
rect:touch(e)
end
return true
end
-- only attach tap listener in the simulator
if (not isDevice) then
circle:addEventListener("tap")
end
-- pass the began phase to the tracking dot
circle:touch(e)
-- return the object for use
return circle
end
-- spawning tracking dots
-- create display group to listen for new touches
local group = display.newGroup()
-- populate display group with objects
local rect = display.newRect( group, 200, 200, 200, 100 )
rect:setFillColor(0,0,255)
rect = display.newRect( group, 300, 300, 200, 100 )
rect:setFillColor(0,255,0)
rect = display.newRect( group, 100, 400, 200, 100 )
rect:setFillColor(255,0,0)
-- keep a list of the tracking dots
group.dots = {}
-- advanced multi-touch event listener
function touch(self, e)
-- get the object which received the touch event
local target = e.target
-- get reference to self object
local rect = self
-- handle began phase of the touch event life cycle...
if (e.phase == "began") then
print( e.phase, e.x, e.y )
-- create a tracking dot
local dot = newTrackDot(e)
-- add the new dot to the list
rect.dots[ #rect.dots+1 ] = dot
-- pre-store the average centre position of all touch points
rect.prevCentre = calcAvgCentre( rect.dots )
-- pre-store the tracking dot scale and rotation values
updateTracking( rect.prevCentre, rect.dots )
-- we handled the began phase
return true
elseif (e.parent == rect) then
if (e.phase == "moved") then
print( e.phase, e.x, e.y )
-- declare working variables
local centre, scale, rotate = {}, 1, 0
-- calculate the average centre position of all touch points
centre = calcAvgCentre( rect.dots )
-- refresh tracking dot scale and rotation values
updateTracking( rect.prevCentre, rect.dots )
-- if there is more than one tracking dot, calculate the rotation and scaling
if (#rect.dots > 1) then
-- calculate the average rotation of the tracking dots
rotate = calcAverageRotation( rect.dots )
-- calculate the average scaling of the tracking dots
scale = calcAverageScaling( rect.dots )
-- apply rotation to rect
rect.rotation = rect.rotation + rotate
-- apply scaling to rect
rect.xScale, rect.yScale = rect.xScale * scale, rect.yScale * scale
end
-- declare working point for the rect location
local pt = {}
-- translation relative to centre point move
pt.x = rect.x + (centre.x - rect.prevCentre.x)
pt.y = rect.y + (centre.y - rect.prevCentre.y)
-- scale around the average centre of the pinch
-- (centre of the tracking dots, not the rect centre)
pt.x = centre.x + ((pt.x - centre.x) * scale)
pt.y = centre.y + ((pt.y - centre.y) * scale)
-- rotate the rect centre around the pinch centre
-- (same rotation as the rect is rotated!)
pt = rotateAboutPoint( pt, centre, rotate, false )
-- apply pinch translation, scaling and rotation to the rect centre
rect.x, rect.y = pt.x, pt.y
-- store the centre of all touch points
rect.prevCentre = centre
else -- "ended" and "cancelled" phases
print( e.phase, e.x, e.y )
-- remove the tracking dot from the list
if (isDevice or e.numTaps == 2) then
-- get index of dot to be removed
local index = table.indexOf( rect.dots, e.target )
-- remove dot from list
table.remove( rect.dots, index )
-- remove tracking dot from the screen
e.target:removeSelf()
-- store the new centre of all touch points
rect.prevCentre = calcAvgCentre( rect.dots )
-- refresh tracking dot scale and rotation values
updateTracking( rect.prevCentre, rect.dots )
end
end
return true
end
-- if the target is not responsible for this touch event return false
return false
end
-- attach pinch zoom touch listener
group.touch = touch
-- listen for touches starting on the touch object
group:addEventListener("touch")
Google search for "corona sdk zoom": implementing pinch zoom rotate
I need to find the intersection between a line and a sphere defined by the following equations
Line: P = P0 + tv, where P0 is the eye of a camera and v is the direction of a ray.
Sphere: (P - Pc)^T (P - Pc) = r^2, where Pc is the center of the sphere and r is the radius
How would I solve for t?
I assume that v is normalized.
The point of closest approach of the line to the center of the sphere occurs at t1:
v . (P0 + t1 v - Pc) = 0
v . (Pc - P0) = t1
At t1 the distance from the line to the center of the sphere is
h = sqrt((Pc - P0)^2 - t1^2)
The intersection with the surface of the sphere will occur (if it occurs at all) at t1 +/- td, where
td^2 + h^2 = r^2
td^2 = r^2 - h^2
= r^2 - (Pc - P0)^2 + t1^2
= r^2 - (Pc - P0)^2 + (v . (Pc - P0))^2
First change the coordinates to a system on the sphere center. P0 -> P0-Pc
Now you have P0=(x0,y0,z0) and the ray coordinates as
x = x0+t*vx
y = y0+t*vy
z = z0+t*vz
and make sure ǁvx,vy,vzǁ=1
The equation of the sphere is x^2+y^2+z^2-R^2 = 0 which is expanded as
t^2 + 2*(vx*x0+vy*y0+vz*z0)*t + (x0^2+y0^2+z0^2-R^2) = 0
t^2 + 2*B*t+C =0
B = vx*x0+vy*y0+vz*z0
C = x0^2+y0^2+z0^2-R^2
t = +√(B^2-C)/2-B
t = -√(B^2-C)/2-B
Which gives the two solutions, p=Pc+P0+v*t for the two t computed.