eine anklickbare Linie



  • Servus liebe Gemeinde,

    sorry für die etwas bescheidene Überschrift, aber mir fiel nix besseres ein. 🙂 Ich hab da mal ein kleines diffiziles Problemchen wofür ich einen Lösungsansatz bzw. ein Tutorial suche. Also mein Problem sieht wie folgt aus: Ich habe ein Bild (TImage)als Hintergrund in dem verschiedene Bilder miteinder verwuselt werden. Darüber liegt jetzt ein anderes TImage. In dem darüberliegenden Bild ein paar Linien reinzuschmieren ist auch noch net das Problem. Das Problem liegt darin, das man die Linien nachdem sie hineingezeichnet wurden wieder anklickbar sein sollen, sodass man sie z.B. Verschieben,löschen,.... kann. Die einzelnen Punkte der Linie(n) hab ich in einer Liste abgespeichert, aber wie zum Geier macht man das das die anklickbar werden. Wer sich das was ich meine net so richtig verstellen kann, ich möchte eine Funktionalität der einzelnen Linie erreichen, wie es z.B. in Visio ist. Ich hab zwar schon stundenlang gegoogelt, aber irgendwie fehlt mir das richtige Wort für so eine Art Linie. Wer da also noch nen Vorschlag hat, immer her damit. 😉

    Für Voschläge, Links, Meinungen, Tutorials ..... und, und, und wäre ich sehr dankbar.

    Vielen Dank schon mal im voraus.

    MfG



  • Hallo

    Das du die einzelnen Punkte in einer Liste speicherst ist schon gut (bei Geraden würde ich nicht jeden einzelnen Punkt sondern nur die Ecken/Enden einer Linie nehmen).
    Alles was du nun noch machen must ist den OnClick-Event des Images benutzen und überprüpen ob die damit gelieferte Position in deiner Liste vorhanden ist. Wenn ja wurde die Linie geklickt.

    bis bald
    akari



  • Wenn du zu jeder Linie nur die Start- und Endkoordinate speicherst kannst du die Steigung der Geraden ausrechnen, bzw. die Geradengleichung der Form g = mx + y bestimmen. Um festzustellen, ob der Benutzer auf die Linie geklickt hat musst du prüfen, ob die Mausposition ein Punkt auf der Geraden ist (oder der Punkt einen gewissen Abstand zur Geraden unterschreitet).
    Ich würde dir noch empfehlen, für jedes Objekt eine Z-Koordinate mitzuführen und die Liste entsprechend dieser Koordinate sortieren. Damit lassen sich einzelne Elemente in der Tiefe anordnen, bei einem Klick auf das Bild fängst du dann mit dem Element an, das den niedrigsten (oder höchsten) Z-Wert hat und arbeitest dich dann durch die Liste.

    Gruß,
    Doc



  • sooo liebe Gemeinde..... ich hab da mal noch was probiert. Und das folgende funkioniert schon mal, halt nur in die falsche Richtung. 😞

    //---------------------------------------------------------------------------
    BOOL CALLBACK isPointinLine(int X,int Y,LPARAM lpData)
    {
      //	TImage* blubb;
      //	blubb = (TImage*)lpData;
    
      if( X == Form1->floating_X && Y == Form1->floating_Y )
    	{
    	 MessageBoxA(NULL,"Treffer","Linie",MB_OK);	//blubb->Canvas->Pixels[X][Y] = clRed;
    	 return true;
    	}
    
    }
    //---------------------------------------------------------------------------
    int  __fastcall TForm1::FindLineToPoint(int X, int Y)
    {
      int count =0;
    for(list<Linien*>::iterator i = LineList->begin(); i != LineList->end(); i++)
       { count++;
       if (	LineDDA( (*i)->From_Point->X, (*i)->From_Point->Y,(*i)->To_Point->X,(*i)->To_Point->Y,(LINEDDAPROC)isPointinLine,(long)Image1) == true )
    		{
    
    		 //MessageBoxA(NULL,IntToStr(count).c_str()  ,"Linie",MB_OK);
    		}
    		else
    			{
    			 //MessageBoxA(NULL,"nicht gefunden","Linie",MB_OK);
    			}
       }
    
    //  return true;
    }
    //---------------------------------------------------------------------------
    

    Den Punkt den ich auf irgendeiner Linie anklicke wird wunderbar markiert, nur wie bekomme ich jetzt raus welche Linie ich angeklickt habe da die Schleife ja immer von Anfang bis Ende läuft und ich ja kein Abbruchkriterium habe.

    MfG TFX



  • Hallo

    Ja dann bau doch ein Abbruchkriterium ein.

    for (...)
    {
      if (/*gefunden*/)
      {
        //auswerten
        break; // verläßt die (innere) For-Schleife
      }
    }
    

    bis bald
    akari



  • Wenn ich ein Abbruchkriterium hätte, wäre die die ganze Geschichte schon zu den Akten gelegt. Da

    LineDDA(...)
    

    aber immer true zurück liefert, selbst wenn man die Linie nicht getroffen hat, habe ich das leider net. In der CALLBACK Function krieg ich zwar mit wann ich den Punkt getroffen habe, aber halt immer noch net die Linie. Und genau da liegt ja noch immer das Problem. Hat da jemand nen besseren/anderen Ansatz für mich??

    MfG TFX



  • ich berechne dazu den (Lotpunkt-) Abstand des Punktes von der Linie.

    double __fastcall LineLotDist(TRealPoint SP,TRealPoint EP, TRealPoint P, TRealPoint &LotP, Boolean DistStrictInLine, int *LotInsideLine)
    {
      double L_2;
      double V;
      double Dist;
      try
      {
        L_2=(EP.X - SP.X)*(EP.X - SP.X) + (EP.Y - SP.Y)*(EP.Y - SP.Y);
        V=(P.X - SP.X)*(EP.X - SP.X) + (P.Y - SP.Y)*(EP.Y - SP.Y);
        V=V / L_2;
    
        LotP.X=SP.X + V * (EP.X - SP.X);
        LotP.Y=SP.Y + V * (EP.Y - SP.Y);
        if (DistStrictInLine)
        { if (V<0)
          { Dist=PointDist(&P,&SP);
          }
          else
          { if (V>1)
            { Dist=PointDist(&P,&EP);
            }
            else
            { Dist=PointDist(&P,&LotP);
            }
          }
        }
        else
        { Dist=PointDist(&P,&LotP);
        }
        if (LotInsideLine!=NULL)
        { if (V<0)
          { *LotInsideLine=-1;
          }
          else
          { if (V>1)
            { *LotInsideLine=1;
            }
            else
            { *LotInsideLine=0;
            }
          }
        }
      }
      catch(...)
      {
        LotP.X=(EP.X + SP.X) / 2;
        LotP.Y=(EP.Y + SP.Y) / 2;
        Dist=PointDist(&P,&LotP);
        if (LotInsideLine!=NULL)
        { *LotInsideLine=0;
        }
      }
      return Dist;
    

    Rückgabewert = Abstand des Punktes (lotrecht) von der Linie.
    Falls Lot ausserhalb der Kontur der Linie liegt, kann der Abstand zum nächsten Ende berechnet werden.

    ******************************************************************************
    TRealPoint ist was analoges zu TPoint, aber mit double Koordinaten X,Y.
    PointDist(...) berechnet den geometrischen Abstand zweier Koordinaten.
    DistStrictInLine steuert, ob virtuelle Lotpunkte benutzt werden sollen oder dann der Abstand zum Ende.
    ******************************************************************************

    Berechne Abstand der ersten Linie zu Punkt ud speichere das als Minimum!
    berechne alle Abstaände zu den anderen Linien und korrigiere Minimum, falls eine Linie näher dran ist.

    - merke die dabei den Index der Linie!

    Am Ende hast Du den Abstand der Linie, die am dichtesten am Punkt liegt.

    Gruss
    Frank



  • @DerAltenburger: danke danke danke.......... und nochmals danke. Das nenn ich mal eine erstklassische Hilfe.


Anmelden zum Antworten