Help needed from a math-geek :)

Just starting out? Need help? Post your questions and find answers here.
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Help needed from a math-geek :)

Post by merendo »

Hello everyone,

I have a problem to solve, and since I'm not that much of a math-freak, I thought someone in this forum might be able to help me.

Here's what I have: Two plain, filled boxes in an image, of which I know all coordinates, width as well as height. However, the boxes may be at completely different heights, i.e. at different Y-coordinates.

What I need: A smooth "flow" between these two boxes. I thought, this could be done with trigonometrics (the flow could perhaps look like a Tangens-graph). Usually the flow will go from the left box to the right box, but there might also be times, when the flow goes the other direction. I guess, I'll need separate treatments for both cases, right? :roll: In any case, the flow will always exit at the right side of the first box, and enter at the left side of the second box.

BTW: This is meant to be a so called energy-flowchart (like this one: https://eed.llnl.gov/flow/images/LLNL_E ... art300.jpg) that depicts the flow of energy from the "source" into converters, losses and useful products from there flowing somewhere else, and so on. I am working on a programme which can draw these. Actually, the only problem that might get in the way now is these "flows" :)

I'm not looking for a complete source code, just some ideas.

Thanks a lot!!
The truth is never confined to a single number - especially scientific truth!
superadnim
Enthusiast
Enthusiast
Posts: 480
Joined: Thu Jul 27, 2006 4:06 am

Post by superadnim »

Hello merendo, I don't see why would you want to complicate things when you could use interpolation + splines to do the job, really, do you have a reason not to use this two ?

You can calculate just a few points and then let the cubic or cosine interpolation do the job in between them, or you could go a little more advanced and use bezier (or other) splines instead.


Cheers.
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Post by merendo »

Having done some research into bezier curves I think I might have found what I was looking for. Thanks for the hint :)
The truth is never confined to a single number - especially scientific truth!
Froggerprogger
Enthusiast
Enthusiast
Posts: 423
Joined: Fri Apr 25, 2003 5:22 pm
Contact:

Post by Froggerprogger »

You could do it more easy by parametric curve if the flow-path isn't too complex (in which case you should use Bezier-Curves).
Idea: Interpolate between start-X(Y, Width, Height) and target-X(Y, Width, Height). This can simply be done by a parameter t that runs from 0.0 to 1.0. This parameter t can be modified (root of, power, etc.) to modify the movements speeding and it can be applied in different ways to x,y,width,height. See the example:

Code: Select all

InitSprite()

OpenWindow(0, 0, 0, 800, 600, "Parametrized Move")
OpenWindowedScreen(WindowID(0), 0, 0, 1024, 768, 1, 0, 0)

Structure BOX
  x.l
  y.l
  w.l
  h.l
EndStructure

start.BOX
start\x = 300
start\y = 200
start\w = 100
start\h = 100

target.BOX
target\x = 600
target\y = 400
target\w = 20
target\h = 200

current.BOX

moveStyle.l = 0
numMoveStyles.l = 4
moveDuration.l = 1500
moveWait.l = 500
moveStart.l
moveName.s

While WindowEvent() <> #PB_Event_CloseWindow
  currentTime.l = ElapsedMilliseconds()
  If moveStart + moveDuration + moveWait < currentTime
    moveStart = currentTime
    moveStyle = (moveStyle+1) % numMoveStyles
  EndIf

  If currentTime <= moveStart + moveDuration
    t.f = (ElapsedMilliseconds() - moveStart) / moveDuration ; t in [0.0,1.0]
    
    Select moveStyle
      Case 0:
        moveName = "Linear"
        current\x = start\x + (target\x - start\x)*t
        current\y = start\y + (target\y - start\y)*t
        current\w = start\w + (target\w - start\w)*t
        current\h = start\h + (target\h - start\h)*t
      Case 1:
        moveName = "Quadratic"
        current\x = start\x + (target\x - start\x)*t*t
        current\y = start\y + (target\y - start\y)*t*t
        current\w = start\w + (target\w - start\w)*t*t
        current\h = start\h + (target\h - start\h)*t*t
      Case 2:
        moveName = "Sqr"
        current\x = start\x + (target\x - start\x)*Sqr(t)
        current\y = start\y + (target\y - start\y)*Sqr(t)
        current\w = start\w + (target\w - start\w)*Sqr(t)
        current\h = start\h + (target\h - start\h)*Sqr(t)
      Case 3:
        moveName = "Mixed"
        current\x = start\x + (target\x - start\x)*t*t
        current\y = start\y + (target\y - start\y)*Sqr(t)
        current\w = start\w + (target\w - start\w)*t*t
        current\h = start\h + (target\h - start\h)*t
    EndSelect
  Else
    current\x = target\x
    current\y = target\y
    current\w = target\w
    current\h = target\h
  EndIf
  
  ClearScreen(0)
  StartDrawing(ScreenOutput())
    DrawingMode(#PB_2DDrawing_Default)
    Box(current\x, current\y, current\w, current\h, RGB(255,255,0))
    
    DrawingMode(#PB_2DDrawing_Outlined)
    Box(start\x, start\y, start\w, start\h, RGB(0,255,0))
    Box(target\x, target\y, target\w, target\h, RGB(255,0,0))
    
    DrawText(5,5,moveName, RGB(200,200,200), 0)
  StopDrawing()
  FlipBuffers() 
  Delay(1)
Wend
Last edited by Froggerprogger on Fri Dec 21, 2007 11:22 am, edited 1 time in total.
%1>>1+1*1/1-1!1|1&1<<$1=1
merendo
Enthusiast
Enthusiast
Posts: 449
Joined: Sat Apr 26, 2003 7:24 pm
Location: Germany
Contact:

Post by merendo »

Sorry, but I get 29 linker errors from your code? :shock: :shock:
The truth is never confined to a single number - especially scientific truth!
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

@Froggerprogger: you need to call InitSprite() in your code before OpenWindowedScreen().
Froggerprogger
Enthusiast
Enthusiast
Posts: 423
Joined: Fri Apr 25, 2003 5:22 pm
Contact:

Post by Froggerprogger »

Oh, thanks! I just added it to the above code. Strange: The missing InitSprite() doesn't produce any compile/link/execute-errors under Linux (Ubuntu).
%1>>1+1*1/1-1!1|1&1<<$1=1
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Hi, Merendo,
This kind of things are interesting problems to me to do.
I had put it in my "todo" list. I have the squeleton plan to perform it professionally, with different sizes of and inclinations of the squares.
Sorry because i don't know if i will do and finish it, but if so i will put it here with complete doc. :)
EDIT 2008-02-03:
Superadnim is right when say about Bezier curves, coz i think it is the easiest way.
Here it is a fast way to do.
But nextly i will do it better because in this way the link-fringe narrows in the middle and then widen, but it should go increasing its width along it approaches to the bigger square side.
The program links the nearer 2 faces of the both rectangles, but i will add nextly the posibility of choose the wanted side.

I think it is no need to explain watching the code.
If you need some explaining don't doubt to ask me.

Code: Select all

; Author: Psychophanta
; Date: Jan 2008

#DEGTORAD=#PI/180.0:#RADTODEG=180.0/#PI
Procedure.f WrapAngle(angle.f); <- wraps a value into [-Pi,Pi] fringe
  !fldpi
  !fadd st0,st0; <- now i have 2*pi into st0
  !fld dword[p.v_angle]
  !fprem1
  !fstp st1
  ProcedureReturn
EndProcedure
Procedure.f ATan2(y.f,x.f)
  !fld dword[p.v_y]
  !fld dword[p.v_x]
  !fpatan
  ProcedureReturn
EndProcedure
Macro StartScreen(title="Full Screen")
  bitplanes.b=32
  SCREENWIDTH.l=GetSystemMetrics_(#SM_CXSCREEN)
  SCREENHEIGHT.l=GetSystemMetrics_(#SM_CYSCREEN)
  If InitMouse()=0 Or InitSprite()=0 Or InitSprite3D()=0 Or InitKeyboard()=0
    MessageRequester("Error","Can't access DirectX",0):End
  EndIf
  While OpenScreen(SCREENWIDTH,SCREENHEIGHT,bitplanes.b,title#)=0
    If bitplanes.b>16:bitplanes.b-8
    ElseIf SCREENHEIGHT>600:SCREENWIDTH=800:SCREENHEIGHT=600
    ElseIf SCREENHEIGHT>480:SCREENWIDTH=640:SCREENHEIGHT=480
    ElseIf SCREENHEIGHT>400:SCREENWIDTH=640:SCREENHEIGHT=400
    ElseIf SCREENHEIGHT>240:SCREENWIDTH=320:SCREENHEIGHT=240
    ElseIf SCREENHEIGHT>200:SCREENWIDTH=320:SCREENHEIGHT=200
    Else:MessageRequester("VGA","Can't open Screen!",0):End
    EndIf
  Wend
EndMacro
Macro InteractivePointerSprite
  CreateSprite(0,16,16);<-The mouse cursor
  StartDrawing(SpriteOutput(0)):BackColor(0)
  Line(0,0,15,10,$CABE2A)
  Line(0,0,5,15,$CABE2A)
  LineXY(5,15,15,10,$CABE2A)
  FillArea(2,2,$CABE2A,$C0C1D0)
  StopDrawing()
EndMacro
Enumeration
  #Rectangle000Ratio=2.4; rectangles width/height
  #SpritesColor000=$8bccaa;<- verde
  #SpritesColor001=$BBAAaa;<- azul verdoso
  #SpritesColor002=$BBAA00;<- violeta claro
  #SpritesColor003=$3399AA;<- verde oscuro
  #SpritesColor004=$EA9700;<- rosa claro
  #SpritesColor005=$9A8800;<- rosa oscuro
  #SpritesColor006=$669A00;<- naranja
  #SpritesColor007=$9A88aa;<- azul
EndEnumeration
Procedure RectangleSprite3D(c.l,size.l,ratio.d,color.l)
  CreateSprite(c,size,size,#PB_Sprite_Texture)
  StartDrawing(SpriteOutput(c)):BackColor(0)
  Protected h.d=size/Sqr(1/ratio/ratio+1),v.d=size/Sqr(ratio*ratio+1)
  Box((size-h)/2,(size-v)/2,h,v,color)
  For t.l=1 To v/2
    Box((size-h)/2+t,(size-v)/2+t,h-2*t,v-2*t,color-t)
  Next
  StopDrawing()
  CreateSprite3D(c,c):ZoomSprite3D(c,size.l,size.l)
EndProcedure
Macro BuildSprites
  RectangleSprite3D(1,512,#Rectangle000Ratio,#SpritesColor000); <- cápsula verde
  RectangleSprite3D(2,512,#Rectangle000Ratio,#SpritesColor001); <- cápsula azul verdoso
  RectangleSprite3D(3,512,#Rectangle000Ratio,#SpritesColor002); <- cápsula violeta claro
  RectangleSprite3D(4,512,#Rectangle000Ratio,#SpritesColor003); <- cápsula verde oscuro
  RectangleSprite3D(5,512,#Rectangle000Ratio,#SpritesColor004); <- cápsula rosa claro
  RectangleSprite3D(6,512,#Rectangle000Ratio,#SpritesColor005); <- cápsula rosa oscuro
  RectangleSprite3D(7,512,#Rectangle000Ratio,#SpritesColor006); <- cápsula naranja
  RectangleSprite3D(8,512,#Rectangle000Ratio,#SpritesColor007); <- cápsula azul
EndMacro
Macro DisplayItems
  Start3D()
  ZoomSprite3D(C(0)\SpriteID,C(0)\Radius*2,C(0)\Radius*2)
  RotateSprite3D(C(0)\SpriteID,C(0)\angledeg,0);<- cápsula
  DisplaySprite3D(C(0)\SpriteID,C(0)\x-C(0)\Radius,C(0)\y-C(0)\Radius,200); <- cápsula
  ZoomSprite3D(C(1)\SpriteID,C(1)\Radius*2,C(1)\Radius*2)
  RotateSprite3D(C(1)\SpriteID,C(1)\angledeg,0);<- cápsula
  DisplaySprite3D(C(1)\SpriteID,C(1)\x-C(1)\Radius,C(1)\y-C(1)\Radius,200); <- cápsula
  Stop3D()
EndMacro
Structure Vector2D
  x.f:y.f
EndStructure
Structure rectangle Extends Vector2D
  SpriteID.l
  angle.f:angledeg.f
  HalfWidth.f:HalfHeight.f
  WidthHeightRatio.f
  StructureUnion
    HalfDiagonal.f:Radius.f
  EndStructureUnion
  distancetocursor.f
  rsidecenterx.f:rsidecentery.f
  dsidecenterx.f:dsidecentery.f
  lsidecenterx.f:lsidecentery.f
  usidecenterx.f:usidecentery.f
EndStructure
Dim C.rectangle(1)
Macro display
  DisplayItems
  DisplayTransparentSprite(0,mx,my)
EndMacro
Procedure.l NewC(*n.rectangle,sprite.l,x.f,y.f,incl.f,Radius.f,WHratio.f=1)
  With *n
  \SpriteID=sprite
  \x=x:\y=y;<-Posición inicial de la cápsula
  \Angle=incl:\AngleDeg=\Angle*#RADTODEG; <- para rotación
  \HalfDiagonal=Radius; <- radius
  \WidthHeightRatio=WHratio; Width/Height proportion
  \HalfWidth=\HalfDiagonal/Sqr(1/\WidthHeightRatio/\WidthHeightRatio+1):\HalfHeight=\HalfDiagonal/Sqr(\WidthHeightRatio*\WidthHeightRatio+1)
  EndWith
  ZoomSprite3D(sprite,Radius*2,Radius*2)
  ProcedureReturn @*n
EndProcedure
Procedure BezierCubicLine(PointList.f(2),res.f=0.02)
  Protected t0.f=0.0,t1.f=1.0,bx0.f=PointList(3,0),by0.f=PointList(3,1),bx.f,by.f
  t0.f+res:t1.f-res
  While t1.f>=0
    bx.f=PointList(0,0)*t0*t0*t0+3*PointList(1,0)*t1*t0*t0+3*PointList(2,0)*t1*t1*t0+PointList(3,0)*t1*t1*t1
    by.f=PointList(0,1)*t0*t0*t0+3*PointList(1,1)*t1*t0*t0+3*PointList(2,1)*t1*t1*t0+PointList(3,1)*t1*t1*t1
    LineXY(bx0,by0,bx,by)
    bx0.f=bx:by0.f=by
    t0.f+res:t1.f-res
  Wend
EndProcedure
Macro AutoSeleccionDeLasCarasMasEnfrentadas
  ;posicionamiento de los puntos principales de la curva de Bezier que será dibujada:
  distx.f=C(1)\x-C(0)\x:disty.f=C(1)\y-C(0)\y; <- vector distancia entre los centros de cada poligono
  argdist.f=Atan2(disty,distx); <- angulo argumento de tal vector distancia
  ;2_1: posicionamiento del punto principal inicial de la curva de bezier:
  Select WrapAngle(C(0)\Angle-argdist.f)*2/#PI; <- se divide entre #PI/2 porque ese es el angulo que forman los lados de la figura geometrica que se trata, en este caso el rectangulo.
  Case 0
    points(0,0)=C(0)\rsidecenterx:points(0,1)=C(0)\rsidecentery
    pointsl(0,0)=C(0)\x+points(0,0)+C(0)\usidecenterx:pointsl(0,1)=C(0)\y+points(0,1)+C(0)\usidecentery
    pointsr(0,0)=C(0)\x+points(0,0)+C(0)\dsidecenterx:pointsr(0,1)=C(0)\y+points(0,1)+C(0)\dsidecentery
  Case -1
    points(0,0)=C(0)\dsidecenterx:points(0,1)=C(0)\dsidecentery
    pointsl(0,0)=C(0)\x+points(0,0)+C(0)\rsidecenterx:pointsl(0,1)=C(0)\y+points(0,1)+C(0)\rsidecentery
    pointsr(0,0)=C(0)\x+points(0,0)+C(0)\lsidecenterx:pointsr(0,1)=C(0)\y+points(0,1)+C(0)\lsidecentery
  Case 1
    points(0,0)=C(0)\usidecenterx:points(0,1)=C(0)\usidecentery
    pointsl(0,0)=C(0)\x+points(0,0)+C(0)\lsidecenterx:pointsl(0,1)=C(0)\y+points(0,1)+C(0)\lsidecentery
    pointsr(0,0)=C(0)\x+points(0,0)+C(0)\rsidecenterx:pointsr(0,1)=C(0)\y+points(0,1)+C(0)\rsidecentery
  Default
    points(0,0)=C(0)\lsidecenterx:points(0,1)=C(0)\lsidecentery
    pointsl(0,0)=C(0)\x+points(0,0)+C(0)\dsidecenterx:pointsl(0,1)=C(0)\y+points(0,1)+C(0)\dsidecentery
    pointsr(0,0)=C(0)\x+points(0,0)+C(0)\usidecenterx:pointsr(0,1)=C(0)\y+points(0,1)+C(0)\usidecentery
  EndSelect
  ;2_2: posicionamiento del punto principal final de la curva de bezier:
  Select WrapAngle(C(1)\Angle-argdist.f)*2/#PI; <- se divide entre #PI/2 porque ese es el angulo que forman los lados de la figura geometrica que se trata, en este caso el rectangulo.
  Case 0
    points(3,0)=C(1)\lsidecenterx:points(3,1)=C(1)\lsidecentery
    pointsl(3,0)=C(1)\x+points(3,0)+C(1)\usidecenterx:pointsl(3,1)=C(1)\y+points(3,1)+C(1)\usidecentery
    pointsr(3,0)=C(1)\x+points(3,0)+C(1)\dsidecenterx:pointsr(3,1)=C(1)\y+points(3,1)+C(1)\dsidecentery
  Case -1
    points(3,0)=C(1)\usidecenterx:points(3,1)=C(1)\usidecentery
    pointsl(3,0)=C(1)\x+points(3,0)+C(1)\rsidecenterx:pointsl(3,1)=C(1)\y+points(3,1)+C(1)\rsidecentery
    pointsr(3,0)=C(1)\x+points(3,0)+C(1)\lsidecenterx:pointsr(3,1)=C(1)\y+points(3,1)+C(1)\lsidecentery
  Case 1
    points(3,0)=C(1)\dsidecenterx:points(3,1)=C(1)\dsidecentery
    pointsl(3,0)=C(1)\x+points(3,0)+C(1)\lsidecenterx:pointsl(3,1)=C(1)\y+points(3,1)+C(1)\lsidecentery
    pointsr(3,0)=C(1)\x+points(3,0)+C(1)\rsidecenterx:pointsr(3,1)=C(1)\y+points(3,1)+C(1)\rsidecentery
  Default
    points(3,0)=C(1)\rsidecenterx:points(3,1)=C(1)\rsidecentery
    pointsl(3,0)=C(1)\x+points(3,0)+C(1)\dsidecenterx:pointsl(3,1)=C(1)\y+points(3,1)+C(1)\dsidecentery
    pointsr(3,0)=C(1)\x+points(3,0)+C(1)\usidecenterx:pointsr(3,1)=C(1)\y+points(3,1)+C(1)\usidecentery
  EndSelect
EndMacro
Macro SeleccionManualDeLasCarasAEnlazar
  points(0,0)=C(0)\rsidecenterx:points(0,1)=C(0)\rsidecentery
  pointsl(0,0)=C(0)\x+points(0,0)+C(0)\usidecenterx:pointsl(0,1)=C(0)\y+points(0,1)+C(0)\usidecentery
  pointsr(0,0)=C(0)\x+points(0,0)+C(0)\dsidecenterx:pointsr(0,1)=C(0)\y+points(0,1)+C(0)\dsidecentery
  points(3,0)=C(1)\lsidecenterx:points(3,1)=C(1)\lsidecentery
  pointsl(3,0)=C(1)\x+points(3,0)+C(1)\usidecenterx:pointsl(3,1)=C(1)\y+points(3,1)+C(1)\usidecentery
  pointsr(3,0)=C(1)\x+points(3,0)+C(1)\dsidecenterx:pointsr(3,1)=C(1)\y+points(3,1)+C(1)\dsidecentery
EndMacro
Procedure.b MouseButtonEdgeDetection(mbutton.b,down.b=1)
  Static mb.b
  If MouseButton(mbutton);<-if current key status is PUSHED
    If mb>>mbutton=0:mb.b|Int(Pow(2,mbutton)):ProcedureReturn down:EndIf;<-if previous key status was NOT PUSHED, then assign previous state to current one, and EXIT.
  ElseIf mb>>mbutton;<-else (if previous key status was PUSHED and current key status is NOT PUSHED):
    mb.b!Int(Pow(2,mbutton)):ProcedureReturn down!1;<-set previous key status to NOT PUSHED.
  EndIf
  ProcedureReturn 0
EndProcedure

;-INITS:
Autoface.b=1
StartScreen("linked figures")
InteractivePointerSprite:MouseLocate(SCREENWIDTH/2,SCREENHEIGHT/2)
BuildSprites
;-MAIN:
NewC(@C(0),Random(7)+1,Random(SCREENWIDTH),Random(SCREENHEIGHT),Random(#PI*2E8)/1E8-#PI,Random(1.2E8)/1E6+5,#Rectangle000Ratio)
NewC(@C(1),Random(7)+1,Random(SCREENWIDTH),Random(SCREENHEIGHT),Random(#PI*2E8)/1E8-#PI,Random(1.2E8)/1E6+5,#Rectangle000Ratio)
Dim Points.f(3,1)
Dim Pointsl.f(3,1); <- tabla para los puntos de una esquina de un lado del cuadrado, la esquina l
Dim Pointsr.f(3,1); <- tabla para los puntos de la otra esquina del mismo lado, la esquina r
Procedure ShowTextAndKeyTest()
  Static showbezierpoints.b,hidetext.b
  Shared pointsl(),pointsr()
  If hidetext=0
    DrawText(0,0,"Put cursor onto poligon and:")
    DrawText(0,20,"hold down Left Mouse Button (LMB) to move it")
    DrawText(0,40,"move mouse wheel to rotate it")
    DrawText(0,60,"3rd mouse button while rotating mouse wheel => modify poligon size")
    DrawText(0,80,"Push and hold LMB onto a linked vertex to modify linking line")
    DrawText(0,100,"Simple click both mouse buttons at the same time to RESTART automatic-linking")
    DrawText(0,120,"Right Mouse Button (RMB) => Toggle between AUTO LINK NEAREST FACES or ASSIGNED LINK FACES")
    DrawText(0,140,"[F11] => Show or hide this text")
    DrawText(0,160,"[F12] => Show or hide Bezier main and control points")
  EndIf
  If showbezierpoints.b
    Circle(pointsl(0,0),pointsl(0,1),3):DrawText(pointsl(0,0),pointsl(0,1),"p0l")
    Circle(pointsl(1,0),pointsl(1,1),3):DrawText(pointsl(1,0),pointsl(1,1),"q0l")
    Circle(pointsl(2,0),pointsl(2,1),3):DrawText(pointsl(2,0),pointsl(2,1),"q1l")
    Circle(pointsl(3,0),pointsl(3,1),3):DrawText(pointsl(3,0),pointsl(3,1),"p1l")
    Circle(pointsr(0,0),pointsr(0,1),3):DrawText(pointsr(0,0),pointsr(0,1),"p0r")
    Circle(pointsr(1,0),pointsr(1,1),3):DrawText(pointsr(1,0),pointsr(1,1),"q0r")
    Circle(pointsr(2,0),pointsr(2,1),3):DrawText(pointsr(2,0),pointsr(2,1),"q1r")
    Circle(pointsr(3,0),pointsr(3,1),3):DrawText(pointsr(3,0),pointsr(3,1),"p1r")
  EndIf
  If KeyboardReleased(#PB_Key_F11):hidetext.b!1:EndIf
  If KeyboardReleased(#PB_Key_F12):showbezierpoints.b!1:EndIf
EndProcedure
Repeat
  ClearScreen(0):ExamineKeyboard():ExamineMouse()
  ;Control de los rectangulos:
  If *managedpoint.Vector2D<2:mx.f=MouseX():my.f=MouseY():EndIf
  If MouseButton(#PB_MouseButton_Right) And MouseButton(#PB_MouseButton_Left):*managedpoint=0:MouseLocate(mx,my):EndIf
  C(0)\distancetocursor=Sqr(Pow(mx.f-C(0)\x,2)+Pow(my.f-C(0)\y,2))
  C(1)\distancetocursor=Sqr(Pow(mx.f-C(1)\x,2)+Pow(my.f-C(1)\y,2))
  If C(0)\distancetocursor<C(0)\HalfWidth Or *selected.rectangle
    C(0)\HalfWidth=C(0)\HalfDiagonal/Sqr(1/C(0)\WidthHeightRatio/C(0)\WidthHeightRatio+1):C(0)\HalfHeight=C(0)\HalfDiagonal/Sqr(C(0)\WidthHeightRatio*C(0)\WidthHeightRatio+1)
    If MouseButton(#PB_MouseButton_Left):If *selected.rectangle=0:*selected.rectangle=@C(0):MouseLocate(C(0)\x,C(0)\y):EndIf:*selected.rectangle\x+MouseDeltaX():*selected.rectangle\y+MouseDeltaY()
    ElseIf MouseButtonEdgeDetection(#PB_MouseButton_Right):Autoface.b!1
    ElseIf MouseButton(#PB_MouseButton_Middle):C(0)\HalfDiagonal+MouseWheel()*4:If C(0)\HalfDiagonal<1:C(0)\HalfDiagonal=1:EndIf
    Else:C(0)\Angle=WrapAngle(C(0)\Angle+MouseWheel()/16):C(0)\AngleDeg=C(0)\Angle*#RADTODEG
      *selected.rectangle=0
    EndIf
  ElseIf C(1)\distancetocursor<C(1)\HalfWidth Or *selected.rectangle
    C(1)\HalfWidth=C(1)\HalfDiagonal/Sqr(1/C(1)\WidthHeightRatio/C(1)\WidthHeightRatio+1):C(1)\HalfHeight=C(1)\HalfDiagonal/Sqr(C(1)\WidthHeightRatio*C(1)\WidthHeightRatio+1)
    If MouseButton(#PB_MouseButton_Left):If *selected.rectangle=0:*selected.rectangle=@C(1):MouseLocate(C(1)\x,C(1)\y):EndIf:*selected.rectangle\x+MouseDeltaX():*selected.rectangle\y+MouseDeltaY()
    ElseIf MouseButtonEdgeDetection(#PB_MouseButton_Right):Autoface.b!1
    ElseIf MouseButton(#PB_MouseButton_Middle):C(1)\HalfDiagonal+MouseWheel()*4:If C(1)\HalfDiagonal<1:C(1)\HalfDiagonal=1:EndIf
    Else:C(1)\Angle=WrapAngle(C(1)\Angle+MouseWheel()/16):C(1)\AngleDeg=C(1)\Angle*#RADTODEG
      *selected.rectangle=0
    EndIf
  EndIf
  ;
  ;1: Asignacion de los vectores que van desde el centroide al centro de cada uno de los lados de un poligono:
  C(0)\rsidecenterx=C(0)\HalfWidth*Cos(C(0)\Angle):C(0)\rsidecentery=C(0)\HalfWidth*Sin(C(0)\Angle)
  C(0)\dsidecenterx=-C(0)\rsidecentery/#Rectangle000Ratio:C(0)\dsidecentery=C(0)\rsidecenterx/#Rectangle000Ratio
  C(0)\lsidecenterx=-C(0)\rsidecenterx:C(0)\lsidecentery=-C(0)\rsidecentery
  C(0)\usidecenterx=-C(0)\dsidecenterx:C(0)\usidecentery=-C(0)\dsidecentery
  ;1_1: Vectores que van desde el centroide al centro de cada uno de los lados del otro cuadrado:
  C(1)\rsidecenterx=C(1)\HalfWidth*Cos(C(1)\Angle):C(1)\rsidecentery=C(1)\HalfWidth*Sin(C(1)\Angle)
  C(1)\dsidecenterx=-C(1)\rsidecentery/#Rectangle000Ratio:C(1)\dsidecentery=C(1)\rsidecenterx/#Rectangle000Ratio
  C(1)\lsidecenterx=-C(1)\rsidecenterx:C(1)\lsidecentery=-C(1)\rsidecentery
  C(1)\usidecenterx=-C(1)\dsidecenterx:C(1)\usidecentery=-C(1)\dsidecentery
  ;
  ;2: Asignar los lados del poligono que estan mas enfocados hacia el otro poligono o bien elegirlas libremente:
  If Autoface
    AutoSeleccionDeLasCarasMasEnfrentadas; <- Asignar los lados del poligono que estan mas enfocados hacia el otro poligono
  Else
    SeleccionManualDeLasCarasAEnlazar; <- elegir libremente los lados del poligono que seran enlazados.
  EndIf
  ;3: posicionamiento de los puntos de control y control manual de los mismos:
  If MouseButtonEdgeDetection(#PB_MouseButton_Left)
    If Sqr(Pow(mx-pointsl(0,0),2)+Pow(my-pointsl(0,1),2))<4:*managedpoint.Vector2D=@pointsl(1,0):*u.Vector2D=@u0.Vector2D
    ElseIf Sqr(Pow(mx-pointsr(0,0),2)+Pow(my-pointsr(0,1),2))<4:*managedpoint.Vector2D=@pointsr(1,0):*u.Vector2D=@u0.Vector2D
    ElseIf Sqr(Pow(mx-pointsl(3,0),2)+Pow(my-pointsl(3,1),2))<4:*managedpoint.Vector2D=@pointsl(2,0):*u.Vector2D=@u1.Vector2D
    ElseIf Sqr(Pow(mx-pointsr(3,0),2)+Pow(my-pointsr(3,1),2))<4:*managedpoint.Vector2D=@pointsr(2,0):*u.Vector2D=@u1.Vector2D
    EndIf
  ElseIf *managedpoint>1
;     *managedpoint\x+(MouseDeltaX()**u\x+MouseDeltaY()**u\y)/Sqr(*u\x**u\x+*u\y**u\y)**u\x:*managedpoint\y+(MouseDeltaX()**u\x+MouseDeltaY()**u\y)/Sqr(*u\x**u\x+*u\y**u\y)**u\y
    *managedpoint\x+MouseDeltaX():*managedpoint\y+MouseDeltaY()
    If MouseButton(#PB_MouseButton_Left)=0:*managedpoint=1:MouseLocate(mx,my):EndIf
  ElseIf *managedpoint=0
    ;Sea |l->| la distancia entre el punto medio del segmento (lado del poliedro) que se enlaza, que es la distancia aproximada entre el principal inicial (P0) y el final (P1):
    lx.f=C(1)\x+points(3,0)-C(0)\x-points(0,0):ly.f=C(1)\y+points(3,1)-C(0)\y-points(0,1);l->
    modl.f=Sqr(lx*lx+ly*ly);|l->|
    modl*0.2
    u0.Vector2D\x=points(0,0)/Sqr(points(0,0)*points(0,0)+points(0,1)*points(0,1)):u0.Vector2D\y=points(0,1)/Sqr(points(0,0)*points(0,0)+points(0,1)*points(0,1))
    u1.Vector2D\x=points(3,0)/Sqr(points(3,0)*points(3,0)+points(3,1)*points(3,1)):u1.Vector2D\y=points(3,1)/Sqr(points(3,0)*points(3,0)+points(3,1)*points(3,1))
    pointsr(1,0)=pointsr(0,0)+u0\x*modl:pointsr(1,1)=pointsr(0,1)+u0\y*modl
    pointsl(1,0)=pointsl(0,0)+u0\x*modl:pointsl(1,1)=pointsl(0,1)+u0\y*modl
    pointsr(2,0)=pointsr(3,0)+u1\x*modl:pointsr(2,1)=pointsr(3,1)+u1\y*modl
    pointsl(2,0)=pointsl(3,0)+u1\x*modl:pointsl(2,1)=pointsl(3,1)+u1\y*modl
  EndIf
  ;4: a dibujar:
  StartDrawing(ScreenOutput())
  FrontColor($eeaaee):BackColor(0)
  BezierCubicLine(@Pointsl.f())
  BezierCubicLine(@Pointsr.f())
  ShowTextAndKeyTest()
  StopDrawing()
  display
  FlipBuffers(0):Delay(16)
Until KeyboardPushed(#PB_Key_Escape)
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Post Reply