環(huán)球新動態(tài):蒙特利爾的麥吉爾大學(xué):計算幾何課程資料
蒙特利爾的麥吉爾大學(xué)的計算幾何課程資料:
(資料圖片)
1. Introduction
When talking about distances, we usually mean the shortest : for instance, if a point X is said to be at distance D of a polygon P, we generally assume that D is the distance from X to the nearest point of P. The same logic applies for polygons : if two polygons A and B are at some distance from each other, we commonly understand that distance as the shortest one between any point of A and any point of B. Formally, this is called a miniminfunction, because the distance D between A and B is given by :
(eq. 1)
This equation reads like a computer program : ? for every point a of A, find its smallest distance to any point b of B ; finally, keep the smallest distance found among all points a?.
That definition of distance between polygons can become quite unsatisfactory for some applications ; let"s see for example fig. 1. We could say the triangles are close to each other considering their shortest distance, shown by their red vertices. However, we would naturally expect that a small distance between these polygons means that no point of one polygon is far from the other polygon. In this sense, the two polygons shown in fig. 1 are not so close, as their furthest points, shown in blue, could actually be very far away from the other polygon. Clearly, the shortest distance is totally independent of each polygonal shape.
Figure 1 :The shortest distance doesn"t consider the whole shape.
Another example is given by fig. 2, where we have the same two triangles at the same shortest distance than in fig. 1, but in different position. It"s quite obvious that the shortest distance concept carries very low informative content, as the distance value did not change from the previous case, while somethingdid change with the objects.
Figure 2 :The shortest distance doesn"t account for the position of the objects.
As we"ll see in the next section, in spite of its apparent complexity, the Hausdorff distance does capture these subtleties, ignored by the shortest distance.
2. What is Hausdorff distance ?
Named after Felix Hausdorff (1868-1942), Hausdorff distance is the ? maximum distance of a set to the nearest point in the other set ? [Rote91]. More formally, Hausdorff distance from set A to set B is a maximinfunction, defined as
(eq. 2)
where a and b are points of sets A and B respectively, and d(a, b) is any metric between these points ; for simplicity, we"ll take d(a, b) as the Euclidian distance between a and b. If for instance A and B are two sets of points, a brute force algorithm would be :
Brute force algorithm :
1. h = 0 2. for every point ai of A, 2.1 shortest = Inf ; 2.2 for every point bj of B dij = d (ai , bj ) if dij < shortest then shortest = dij 2.3 if shortest > h then h = shortestFigure 3 :Hausdorff distance on point sets.
This is illustrated in fig. 3 : just click on the arrow to see the basic steps of this computation. This algorithm obviously runs in O(n m) time, with n and m the number of points in each set. It should be noted that Hausdorff distance is oriented (we couldsay asymmetricas well), which means that most of times h(A, B) is not equal to h(B, A). This general condition also holds for the example of fig. 3, as h(A, B) = d(a1, b1), while h(B, A) = d(b2, a1). This asymmetry is a property of maximin functions, while minimin functions are symmetric. A more general definition of Hausdorff distance would be :
H (A, B) = max { h (A, B), h (B, A) }(eq. 3)
which defines the Hausdorff distance betweenA and B, while eq. 2 applied to Hausdorff distance fromA toB (also called directedHausdorff distance). The two distances h(A, B) and h(B, A) are sometimes termed as forwardand backwardHausdorff distances of A to B. Although the terminology is not stable yet among authors, eq. 3 is usually meant when talking about Hausdorff distance. Unless otherwise mentionned, from now on we will also refer to eq. 3 when saying "Hausdorff distance".
If sets A and B are made of lines or polygons instead of single points, then H(A, B) applies to all defining points of these lines or polygons, and not only to their vertices. The brute force algorithm could no longer be used for computing Hausdorff distance between such sets, as they involve an infinite number of points.
So, what about the polygons of fig. 1 ?Remember, some of their points were close, but not all of them. Hausdorff distance gives an interesting measure of their mutual proximity, by indicating the maximal distance between anypoint of one polygon to the other polygon. Better than the shortest distance, which applied only to onepoint of each polygon, irrespective of all other points of the polygons.
Figure 4 :Hausdorff distance shown around extremum of each triangles of fig. 1. Each circle has a radius of H( P1 , P2).
The other concern was the insensitivity of the shortest distance to the position of the polygons. We saw that this distance doesn"t consider at all the disposition of the polygons. Here again, Hausdorff distance has the advantage of being sensitive to position, as shown in fig.5.
Figure 5 :Hausdorff distance for the triangles of fig. 4 at the same shortest distance, but in different position.
3. Computing Hausdorff distance between convex polygons
3.1 Assumptions
Throughout the rest of our discussion, we assume the following facts about polygons A and B :
Polygons A and B are simple convex polygons ; Polygons A and B are disjoint from each other, that is : - they don"t intersect together ; - no polygon contains the other.
3.2 Lemmas
The algorithm explained in the next section is based on three geometric observations, presented here. In order to simplify the text, we assume two points aand bthat belong respectively to polygons A and B, such that :
d (a, b) = h (A, B)
In simple words, ais the furthest point of polygon A relative to polygon B, while bis the closest point of polygon B relative to polygon A.
Lemma 1a :The perpendicular to abat ais a supporting line of A, and A is on the same side as B relative to that line.
Proof of lemma 1a
Lemma 1b :The perpendicular to abat bis a supporting line of B, and aand B are on different sides relative to that line.
Proof of lemma 1b
Lemma 2 :There is a vertex xof A such that the distance from xto B is equal to h (A, B).
Proof of lemma 2
Lemma 3 :Let bi be the closest point of B from a vertex a i of A. If μ is the moving direction (clockwise or counterclockwise) from bi to bi+1 then, for a complete cycle through all vertices of A, μ changes no more than twice.
Proof of lemma 3
3.3 Algorithm
The algorithm presented here was proposed by [Atallah83]. Its basic strategy is to compute successively h(A,B) and h(B, A) ; because of lemma 2, there is no need to query every point of the starting polygon, but only its vertices.
An important fact used by this algorithm is that a closest point can only be a vertex of the target polygon, or the foot zof a line perpendicular to one of its edges. This fact suggests a function to check for the existence of a possible closest point. Given a source point aand a target edge defined by a point b1 and a vertex b2 :
Function z = CheckForClosePoint (a, b1 , b2 ) :Compute the position zwhere the line that passes through b1 and b2 crosses its perpendicular through a; if zis between b1 b2 then return z; else compute at b2 a line P perpendicular to the line ab2 ; if P is a supporting line of B then return b2 ; else return NULL.
That function obviously uses lemma 1b to decide whether or not the closest point of B might be located on the target edge, that should be close to a. It also supposes that the source point aand b2 are not located on different sides of the perpendicular to [b1b2 ] at b1, accordingly to lemma 3. Now we are ready for the main algorithm ; the vertices of both polygons are presumed to be enumerated counterclockwise :
Algorithm for computing h(A, B) :
1. From a1, find the closest point b1 and compute d1 = d ( a1, b1 ) 2. h(A, B) = d1 3. for each vertex ai of A, 3.1 if ai+1 is to the left of aibi find bi+1 , scanning B counterclockwise with CheckForClosePoint from bi if ai+1 is to the right of aibi find bi+1 , scanning B clockwise with CheckForClosePoint from bi if ai+1 is anywhere on aibi bi+1 = bi 3.2 Compute di+1 = d (ai+1 , bi+1 ) 3.3 h (A, B) = max { h (A, B), di+1 }
3.4 Complexity
If polygons A and B respectively have n and m vertices, then :
Step 1 can clearly be done in O(m) time ;Step 2 takes constant time O(1) ;Step 3 will be executed (n-1) times, that is O(n) ;Step 3.1 will not be executed in totalmore than O(2m). This is a consequence of lemma 3, which guarantees that polygon B can not be scanned more than twice ;Steps 3.2 and 3.3 are done in constant time O(1) ;
So the algorithm for computing h(A, B) takes :
O(m) + O(n) + O(2m) = O(n+m)
To find H(A, B), the algorithm needs to executed twice ; the total complexity for computing Hausdorff distance then stays linear to O(n+m).
3.5 Interactive applet
This applet illustrates the algorithm for computing h(A,B). You only need to draw two polygons, and then press the "step" or "run" button. Left click to define a new vertex, and close the polygon by clicking near the first vertex. Polygon A is the first one you draw, in green, while polygon B appears next, in red. The algorithm was slightly modified to make it more appealing visually. Even if this algorithm is intended for two polygons totally separated from each other, it also works when B is inside A. However, it won"t work if A is inside of B, or when A and B are partially intersecting. You"re allowed anyway to try these cases to see what happens ! When defining your polygons, you will see a yellow area that indicates where you can add the next vertex, so the polygon keeps convex. The applet won"t let you define a non-convex polygon.
Please notice that the first time you draw the second half of a polygon, you will have to wait a few seconds until the Jama package loads.
import java.awt.*;
import java.applet.Applet;
import java.util.Vector;
import java.lang.Math;
import Jama.*;
public class Hausdorff extends Applet
{
PolyArea area;
Panel control;
Button runStop;
boolean running;
TextField comment;
public void init()
{
setLayout (new BorderLayout());
comment = new TextField ("", 60);
comment.setEditable (false);
area = new PolyArea (comment);
add ("Center", area);
control = new Panel();
control.add (new Button ("step"));
runStop = new Button ("run");
control.add (runStop);
control.add (new Button ("reset"));
control.add (comment);
add("South", control);
running = false;
}
public boolean action (Event evt, Object arg)
{
if ("step".equals(arg))
area.stepAlgo();
if ("run".equals(arg))
{
runStop.setLabel ("stop");
startAnim();
running = true;
}
if ("stop".equals(arg))
{
runStop.setLabel ("run");
stopAnim();
running = false;
}
if ("reset".equals(arg))
{
remove (area);
stopAnim();
area = new PolyArea (comment);
add ("Center", area);
runStop.setLabel ("run");
validate();
stopAnim();
running = false;
}
return true;
}
public void start()
{
if (running)
startAnim();
}
public void stop()
{
stopAnim();
}
public void startAnim()
{
if (area.animator == null)
{
area.animator = new Thread (area);
}
area.animator.start();
}
public void stopAnim()
{
area.animator = null;
}
public void paint(Graphics g) {
Dimension d = getSize();
g.setColor (Color.black);
g.drawRect(0,0, d.width - 1, d.height - 1);
}
/* This is used to leave room to the black box painted in
* the paint() method. If we don"t do that, it is overwritten.
*/
public Insets getInsets() {
return new Insets(3,3,3,3);
}
}
//=============================================================================
/*
* The PolyArea class defines an area that will hold our two polygons.
* It will first create them by catching mouse clicks events and adding
* the points to the polygons, and it will then run the algorithm on the
* polygons.
*/
class PolyArea extends Canvas implements Runnable
{
Dimension offDimension;
Image offImage;
Graphics offGraphics;
TextField comment;
public Thread animator;
FConvexPoly poly1, poly2;
int nextStep;
int currentV1;
FPoint bestV1, bestV2, currentV2;
double bestLength;
int currentRegBase;
boolean band;
Polygon currentRegion;
boolean trigo;
public PolyArea (TextField comment)
{
animator = null;
this.comment = comment;
setBackground (Color.white);
poly1 = new FConvexPoly (Color.green);
poly2 = new FConvexPoly (Color.red);
nextStep = -1;
currentV1 = currentRegBase = -1;
bestV1 = bestV2 = currentV2 = null;
band = false;
currentRegion = null;
bestLength = 0;
trigo = true;
comment.setText ("Please enter the first polygon");
comment.setBackground (new Color (220, 255, 230));
comment.setForeground (Color.black);
}
public boolean handleEvent (Event e)
{
switch (e.id)
{
case Event.MOUSE_DOWN:
if (nextStep == -1)
{
if (! poly1.isClosed())
{
poly1.addPoint (new FPoint (e.x, e.y));
if (poly1.isClosed())
{
comment.setText ("Please enter the second polygon");
comment.setBackground (new Color (255, 220, 220));
}
}
else
{
poly2.addPoint (new FPoint (e.x, e.y));
if (poly2.isClosed())
{
comment.setText ("Press step or run to see the algorithm");
comment.setBackground (new Color (255, 255, 220));
nextStep = 0;
}
}
}
repaint();
return true;
default:
return false;
}
}
/* This method performs a step in the algorithm. It is called either
* by the applet when the "step" button is clicked, or by the animator
* thread if this one is running. */
public void stepAlgo ()
{
Point p;
switch (nextStep)
{
case 0:
comment.setText ("Searching for the first vertex");
comment.setBackground (new Color (255, 235, 200));
currentV1 = 0;
currentRegBase = 0;
band = false;
makeRegion();
p = poly1.getPoint (currentV1);
if (currentRegion.inside (p.x, p.y))
nextStep = 2;
else
nextStep = 1;
repaint();
break;
case 1:
if (! band)
band = true;
else
{
currentRegBase++;
band = false;
}
makeRegion();
p = poly1.getPoint (currentV1);
if (currentRegion.inside (p.x, p.y))
nextStep = 2;
else
nextStep = 1;
repaint();
break;
case 2:
comment.setText ("Computing length");
comment.setBackground (new Color (255, 220, 255));
makeV2();
bestV1 = poly1.getFPoint (currentV1);
bestV2 = currentV2;
bestLength = new FVector (bestV1, bestV2).length();
nextStep = 3;
repaint();
break;
case 3:
comment.setText ("Searching for the next vertex");
comment.setBackground (new Color (255, 235, 200));
if (new FVector (currentV2, poly1.getFPoint (currentV1)).isTrigo
(new FVector (currentV2, poly1.getFPoint (currentV1 + 1))))
trigo = true;
else
trigo = false;
currentV1++;
currentV2 = null;
if (poly1.getFPoint (currentV1) == poly1.getFPoint (0))
nextStep = 7;
else
{
p = poly1.getPoint (currentV1);
if (currentRegion.inside (p.x, p.y))
nextStep = 5;
else
nextStep = 4;
}
repaint();
break;
case 4:
if ((trigo || !poly2.isTrigo()) && !(trigo && !poly2.isTrigo()))
if (! band)
band = true;
else
{
currentRegBase++;
band = false;
}
else
if (! band)
{
currentRegBase--;
band = true;
}
else
band = false;
makeRegion();
p = poly1.getPoint (currentV1);
if (currentRegion.inside (p.x, p.y))
nextStep = 5;
else
nextStep = 4;
repaint();
break;
case 5:
comment.setText ("Comparing this length with the previous best");
comment.setBackground (new Color (255, 220, 255));
makeV2();
if (new FVector (poly1.getFPoint (currentV1), currentV2).length() > bestLength)
nextStep = 6;
else
nextStep = 3;
repaint();
break;
case 6:
comment.setText ("This is the new best length");
comment.setBackground (new Color (220, 255, 220));
bestV1 = poly1.getFPoint (currentV1);
bestV2 = currentV2;
bestLength = new FVector (bestV1, bestV2).length();
nextStep = 3;
repaint();
break;
case 7:
comment.setText ("Hausdorff distance from poly 1 to poly 2");
comment.setBackground (new Color (220, 220, 255));
currentV1 = -1;
currentV2 = null;
currentRegion = null;
animator = null;
repaint();
break;
default:
break;
}
}
/* The paint method draws the current state of the algorithm in the
* given Graphics, including the two polygons, the yellow region and
* the important points. */
public void paint (Graphics g)
{
poly1.fill (g);
poly2.fill (g);
if (currentRegion != null)
{
g.setColor (Color.yellow);
g.fillPolygon (currentRegion);
}
poly1.draw (g);
poly2.draw (g);
if (currentV1 >= 0)
{
Point p = poly1.getPoint (currentV1);
g.setColor (Color.blue);
g.drawOval (p.x-5, p.y-5, 10, 10);
}
if (currentV2 != null)
{
Point p1 = poly1.getPoint (currentV1);
Point p2 = currentV2.getPoint();
g.setColor (Color.blue);
g.drawOval (p2.x-5, p2.y-5, 10, 10);
g.setColor (Color.blue);
g.drawLine (p1.x, p1.y, p2.x, p2.y);
}
if (bestV1 != null)
{
Point p1 = bestV1.getPoint();
Point p2 = bestV2.getPoint();
g.setColor (Color.magenta);
g.drawLine (p1.x, p1.y, p2.x, p2.y);
}
}
/* When called by the AWT, the update method clears its offscreen
* buffer, calls paint() to draw in it, and then copies the buffer to the
* screen. */
public void update (Graphics g)
{
Dimension d = size();
if ((offGraphics == null) ||
(d.width != offDimension.width) ||
(d.height != offDimension.height))
{
offDimension = d;
offImage = createImage(d.width, d.height);
offGraphics = offImage.getGraphics();
}
offGraphics.setColor (getBackground());
offGraphics.fillRect (0, 0, d.width, d.height);
paint (offGraphics);
g.drawImage (offImage, 0, 0, this);
}
/* This method is called in the algorithm to make the new
* yellow polygon that corresponds to the sweeping yellow
* region. */
void makeRegion()
{
Polygon region;
FPoint p1, p2;
FVector v1, v2, edge;
p1 = poly2.getFPoint (currentRegBase);
p2 = poly2.getFPoint (currentRegBase + 1);
edge = new FVector (p1, p2);
if (poly2.isTrigo())
v1 = edge.normal().mult(-1);
else
v1 = edge.normal();
if (band)
{
currentRegion = FConvexPoly.infiniteRegion (p1, v1, p2, v1);
}
else
{
p2 = poly2.getFPoint (currentRegBase - 1);
edge = new FVector (p2, p1);
if (poly2.isTrigo())
v2 = edge.normal().mult(-1);
else
v2 = edge.normal();
currentRegion = FConvexPoly.infiniteRegion (p1, v1, p1, v2);
}
}
/* This method creates the new end of the current smallest distance
* that"s on the red polygon. If the current vertex of the green polygon
* is in a yellow sector, it corresponds to the current vertex of the red
* polygon. If it is in a band, it is the foot of the perpendicular to the
* current edge of the red polygon that goes through the vertex. */
void makeV2()
{
if (! band)
currentV2 = poly2.getFPoint (currentRegBase);
else
{
FPoint p1, p2;
FVector vBase;
FLine baseLine, perpendicular;
p1 = poly2.getFPoint (currentRegBase);
p2 = poly2.getFPoint (currentRegBase + 1);
vBase = new FVector (p1, p2);
baseLine = new FLine (p1, vBase);
p2 = poly1.getFPoint (currentV1);
perpendicular = new FLine (p2, vBase.normal());
currentV2 = baseLine.intersect (perpendicular);
}
}
/* The run method is called by the virtual machine to perform the
* automated animation of the algorithm. It calls the stepAlgo() method
* three times per second to animate the algorithme. */
public void run()
{
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
long startTime = System.currentTimeMillis();
while (Thread.currentThread() == animator)
{
stepAlgo();
try
{
startTime += 300;
Thread.sleep (Math.max (0, startTime-System.currentTimeMillis()));
}
catch (InterruptedException e) { break; }
}
}
}
//=============================================================================
/*
* The FConvexPoly class represents a convex polygon.
*/
class FConvexPoly
{
public Vector v;
boolean closed;
boolean trigo;
Color polyColor;
public FConvexPoly (Color c)
{
v = new Vector();
closed = false;
trigo = false;
polyColor = c;
}
public boolean isClosed ()
{
return closed;
}
public boolean isTrigo ()
{
return trigo;
}
public Point getPoint (int i)
{
return ((FPoint) v.elementAt (MesMath.mod (i, v.size()))).getPoint();
}
public FPoint getFPoint (int i)
{
return (FPoint) v.elementAt (MesMath.mod (i, v.size()));
}
public void addPoint (FPoint p)
{
if (! closed)
{
if (v.size() < 3)
{
v.addElement (p);
if (v.size() == 3)
trigo = firstVector().isTrigo (lastVector());
}
else
{
if (p.equals ((FPoint) v.firstElement()))
closed = true;
else
{
if (isNextOK (p))
v.addElement (p);
}
}
}
}
public boolean isNextOK (FPoint p)
{
FVector next;
next = new FVector ((FPoint) v.firstElement(), p);
if (firstVector().isTrigo (next) != trigo)
return false;
next = new FVector ((FPoint) v.lastElement(), p);
if (lastVector().isTrigo (next) != trigo)
return false;
next = new FVector ((FPoint) v.firstElement(), p);
if (boundVector().isTrigo (next) == trigo)
return false;
else
return true;
}
public FVector firstVector()
{
return new FVector ((FPoint) v.elementAt (0),
(FPoint) v.elementAt (1));
}
public FVector lastVector()
{
return new FVector ((FPoint) v.elementAt (v.size()-2),
(FPoint) v.elementAt (v.size()-1));
}
public FVector boundVector()
{
return new FVector ((FPoint) v.elementAt (v.size()-1),
(FPoint) v.elementAt (0));
}
/* Draw the filled polygon on the given graphics. */
public void fill (Graphics g)
{
Polygon p = new Polygon();
Point pt, pt2;
FPoint fpt;
for (int a=0; a<V.SIZE(); a++)<="" code="">
{
pt = ((FPoint) v.elementAt (a)).getPoint();
p.addPoint (pt.x, pt.y);
}
g.setColor (polyColor);
g.fillPolygon (p);
if (!closed && v.size() >= 3)
{
Polygon nextReg = new Polygon();
if (lastVector().isTrigo (firstVector()) == trigo)
{
pt = ((FPoint) v.firstElement()).getPoint();
pt2 = ((FPoint) v.lastElement()).getPoint();
nextReg.addPoint (pt.x, pt.y);
nextReg.addPoint (pt2.x, pt2.y);
FLine l1 = new FLine ((FPoint) v.firstElement(),
firstVector());
FLine l2 = new FLine ((FPoint) v.lastElement(),
lastVector());
fpt = l1.intersect (l2);
pt = fpt.getPoint();
nextReg.addPoint (pt.x, pt.y);
}
else
{
FVector firstInv = firstVector().mult (-1);
nextReg = infiniteRegion ((FPoint) v.firstElement(),
firstInv,
(FPoint) v.lastElement(),
lastVector());
}
g.setColor (Color.yellow);
g.fillPolygon (nextReg);
}
}
/* Draw the outline of the polygon on the given graphics. */
public void draw (Graphics g)
{
Point pt, pt2;
g.setColor (Color.blue);
if (v.size() > 0)
{
pt = pt2 = ((FPoint) v.firstElement()).getPoint();
for (int a=0; a<V.SIZE()-1; a++)<="" code="">
{
pt2 = ((FPoint) v.elementAt (a+1)).getPoint();
g.drawLine (pt.x, pt.y, pt2.x, pt2.y);
pt = pt2;
}
pt = ((FPoint) v.firstElement()).getPoint();
if (closed)
g.drawLine (pt.x, pt.y, pt2.x, pt2.y);
else
{
g.setColor (Color.red);
g.drawOval (pt.x-5, pt.y-5, 10, 10);
}
}
}
/* This method returns a Polygon that will look infinite when
* drawn by the Graphics methods. This should not be in here, it should
* not be a static method, but it worked so I left it this way...*/
public static Polygon infiniteRegion (FPoint p1, FVector v1, FPoint p2, FVector v2)
{
Polygon p = new Polygon();
Point pt;
double length;
FVector middle;
pt = p1.getPoint();
p.addPoint (pt.x, pt.y);
if (! p1.equals (p2))
{
pt = p2.getPoint();
p.addPoint (pt.x, pt.y);
}
length = v2.length();
pt = new Point ((int) (p2.x + (v2.x / length * 2000)),
(int) (p2.y + (v2.y / length * 2000)));
p.addPoint (pt.x, pt.y);
middle = (v1.mult (1/v1.length())).add (v2.mult (1/v2.length()));
length = middle.length();
pt = new Point ((int) (middle.x + (middle.x / length * 2000)),
(int) (middle.y + (middle.y / length * 2000)));
p.addPoint (pt.x, pt.y);
length = v1.length();
pt = new Point ((int) (p1.x + (v1.x / length * 2000)),
(int) (p1.y + (v1.y / length * 2000)));
p.addPoint (pt.x, pt.y);
return p;
}
}
//=============================================================================
/*
* The FPoint class represents a point in the plane.
*/
class FPoint
{
static double EPSILON = 10;
double x;
double y;
public FPoint (double x, double y)
{
this.x = x;
this.y = y;
}
public FPoint (int x, int y)
{
this.x = (double) x;
this.y = (double) y;
}
public FPoint (Point p)
{
this.x = (double) p.x;
this.y = (double) p.y;
}
public boolean equals (FPoint p)
{
if (new FVector (this, p).length() < EPSILON)
return true;
else
return false;
}
public Point getPoint()
{
return new Point ((int) x, (int) y);
}
}
//=============================================================================
/*
* The FVector class provides a basic 2-dimensional vector type,
* along with some uselful methods.
*/
class FVector
{
double x;
double y;
public FVector (double x, double y)
{
this.x = x;
this.y = y;
}
public FVector (FPoint a, FPoint b)
{
x = b.x - a.x;
y = b.y - a.y;
}
/* Returns the dot product of the vector with v. */
public double dot (FVector v)
{
return x * v.x + y * v.y;
}
/* Returns the vector normal to this vector. */
public FVector normal()
{
return new FVector (-y, x);
}
/* Return true if v makes an angle with the vector in the
* trigonometric direction (a left turn). */
public boolean isTrigo (FVector v)
{
if (dot (v.normal()) <= 0)
return true;
else
return false;
}
public double length()
{
return Math.sqrt (x*x + y*y);
}
public FVector add (FVector v)
{
return new FVector (x + v.x, y + v.y);
}
public FVector mult (double a)
{
return new FVector (x*a, y*a);
}
}
//=============================================================================
/*
* The FLine class represents a line. Here, it is only used to call
* its intersect() method to compute the intersection of two lines.
*/
class FLine
{
/* The line is under the form ax+by=c */
double a;
double b;
double c;
/*
* Creates a new FLine that goes through p and is supported
* by v.
*/
public FLine (FPoint p, FVector v)
{
FVector vn = v.normal();
a = vn.x;
b = vn.y;
c = a * p.x + b * p.y;
}
/* Creates a new FLine that goes through both a and b. */
public FLine (FPoint a, FPoint b)
{
this (a, new FVector (a, b));
}
/*
* The methode computes the intersection point of two
* lines. We use the JAMA matrix package (see
*
* http://math.nist.gov/javanumerics/jama/
* for details).
*/
public FPoint intersect (FLine l)
{
double[][] tabA = {{ a, b},
{l.a, l.b}};
Matrix matA = new Matrix (tabA);
double[][] tabB = {{ c},
{l.c}};
Matrix matB = new Matrix (tabB);
double[][] tabX = (matA.solve (matB)).getArray();
return new FPoint (tabX[0][0], tabX[1][0]);
}
}
//=============================================================================
/*
* The MesMath class is an abstract class that is used to perform
* division related operations on integers. I haven"t been able to tell
* java that I needed my divisions to be rounded toward minus infinity
* rather than zero, so I"ve had to do it myself.
*/
abstract class MesMath
{
public static int div (int a, int b)
{
if (a >= 0)
return a / b;
else
return (a - b + 1) / b;
}
public static int mod (int a, int b)
{
return a - div (a, b) * b;
}
}
標(biāo)簽: 蒙特利爾
相關(guān)推薦:
精彩放送:
- []環(huán)球新動態(tài):蒙特利爾的麥吉爾大學(xué):計算幾何課程資料
- []全球速訊:視頻編碼中畫面質(zhì)量控制中最重要的部分——DataRate
- []粒子群算法原理 基于numpy6.2的粒子群算法詳解
- []世界熱議:NSM開發(fā)總結(jié) NSM項目的技術(shù)培訓(xùn)
- []世界訊息:什么是驅(qū)動程序?驅(qū)動程序和光驅(qū)有什么區(qū)別?
- []今日播報!三星i458怎么樣?報價多少?三星i458市場報價及測評
- []當(dāng)前最新:mac卡巴斯基激活碼怎么用?免費領(lǐng)取教程來了
- []【天天時快訊】神州行幸福卡是什么?神州行幸福卡詳情介紹
- []天天觀熱點:華僑城西部投資掛牌劍門關(guān)華僑城旅游公司2億股股份 底價4.75億元
- []環(huán)球快消息!美高梅國際酒店集團(tuán)2022年度收益凈額6.74億美元 同比減少44%
- []女演員長相有多重要?看《我們的日子》里李小冉和齊歡就知道了
- []美物科技(WNW.US)收到納斯達(dá)克股價不合規(guī)通知
- []觀速訊丨社保基數(shù)1萬多什么水平(社保基數(shù)8000是什么檔次)
- []信用卡2萬額度算高嗎(信用卡2萬額度算高嗎)
- []天天通訊!交強險9月19日新規(guī)
- []焦點速遞!港財政司副司長黃偉綸對香港保持國際金融中心地位充滿信心?
- []環(huán)球快看:哈工智能重組預(yù)案出爐 擬收購宜春鋰企切入新能源業(yè)務(wù)
- []微速訊:2020年車險保費新政策
- []環(huán)球新消息丨出險一次第二年保費怎么算2020
- []天天資訊:關(guān)于春天的味道作文600字匯總5篇
- []江蘇自貿(mào)區(qū)板塊2月8日跌1.42%,連云港領(lǐng)跌,主力資金凈流出9927.05萬元
- []微信昵稱婦女簡單大方 女人簡單大方的微信網(wǎng)名匯總
- []2022教師節(jié)手抄報簡單好看字少
- []觀焦點:鄂臺青年武當(dāng)文化研學(xué)營開營
- []當(dāng)前速讀:有房貸的房子可以拍賣嗎?(房貸沒還完可以拍賣嗎)
- []全球快看點丨單位為什么不給員工上生育險(單位不給男職工交生育險)
- []貝因美大股東權(quán)益再現(xiàn)變動 4.44%持股簽署表決權(quán)委托協(xié)議
- []環(huán)球快消息!交通信用卡改還款日期怎么改(交通信用卡怎么改還款日期)
- []全球微頭條丨營業(yè)外支出和管理費用的區(qū)別(營業(yè)外支出和管理費用的區(qū)別)
- []頭條焦點:中際旭創(chuàng):2月7日公司高管王軍減持公司股份合計10000股
- []天天簡訊:澄天偉業(yè):2月7日公司高管景在軍減持公司股份合計14萬股
- []環(huán)球今日訊!南網(wǎng)能源:截至2023年1月31日,公司合并普通賬戶和融資融券信用賬戶的持有人數(shù)為156,602
- []速訊:北京2023年首場土拍收官:央國企仍是主角,越秀“再北上”59億元拿下兩宗
- []世界熱議:中建智地17.2億元底價拍得北京房山良鄉(xiāng)大學(xué)城地塊
- []觀察:科拓生物:2月7日公司高管劉曉軍減持公司股份合計8萬股
- []游族網(wǎng)絡(luò)(002174)股東林漓、林芮璟、林小溪合計質(zhì)押5494.94萬股,占總股本6%
- []電飯鍋做面包的方法
- []焦點播報:合肥泰康人壽保險公司怎么樣(合肥泰康人壽保險公司怎么樣)
- []環(huán)球熱資訊!謝楊春等:優(yōu)質(zhì)供應(yīng)帶動,杭州土拍迎“小陽春”
- []世界觀焦點:越秀2023開年狂飆北京,59億激進(jìn)補倉,石景山死磕中海
- []半數(shù)地塊溢價成交 北京第五批集中供地收官
- []大元泵業(yè):2月6日公司高管崔樸樂減持公司股份合計2萬股
- []每日頭條!山西太原:公積金貸款首房首付比例為20%
- []璞泰來:2月8日公司高管陳衛(wèi)增持公司股份合計9.25萬股
- []越秀以33.12億元+4.5萬平現(xiàn)房銷售面積競得北京昌平回龍觀地塊
- []天馬科技:2月7日公司高管何騰飛、曾麗莉增持公司股份合計3.52萬股
- []當(dāng)前頭條:力合科技:公司主營業(yè)務(wù)為環(huán)境監(jiān)測系統(tǒng)研發(fā)、生產(chǎn)和銷售及運營服務(wù)
- []天天短訊!和醫(yī)保卡綁定的銀行卡丟了怎么辦理(和醫(yī)保卡綁定的銀行卡丟了怎么辦)
- []最資訊丨青島東李世園板塊萬竹云峰項目再流拍 底價已降至3.56億
- []廈門鎢業(yè)等三方加強戰(zhàn)略合作 推進(jìn)大湖塘鎢礦開發(fā)
- []世界觀焦點:華僑城調(diào)整“18僑城06”票面利率至1.5% 并開啟回售
- []捷安高科:公司暫未涉及ChatGPT的產(chǎn)品和技術(shù)
- []快看:外地人在長沙買房怎么交社保(外地人怎么在長沙買房)
- []世界快看點丨職工醫(yī)保補繳會返還嗎(補繳醫(yī)保有返錢嗎)
- []免費安全工作總結(jié)(優(yōu)選9篇)
- []全球熱點!“20榮盛地產(chǎn)MTN002”持有人會議通過變更債券本息兌付安排等議案
- []重點聚焦!深圳重啟積分入戶 專家預(yù)計未來住房需求會明顯增加
- []全球快訊:華大九天:公司主要從事EDA工具軟件的開發(fā)、銷售及相關(guān)服務(wù)
- []茂業(yè)商業(yè)子公司與關(guān)聯(lián)方簽合計700萬元物業(yè)服務(wù)協(xié)議
- []杭州網(wǎng)絡(luò)零售額首次突破萬億 直播相關(guān)企業(yè)注冊量全國第一
- []環(huán)球關(guān)注:紅星美凱龍為常州子公司7.07億債務(wù)提供擔(dān)保
- []全球信息:中電興發(fā):公司作為智慧城市全面解決方案提供商和運營服務(wù)商,被納入深證人工智能(AI)50指數(shù)
- []【全球獨家】志特新材:公司的定期報告會對股東總?cè)藬?shù)進(jìn)行披露,屆時請關(guān)注披露公告
- []今日熱搜:醫(yī)保卡不在紅名單怎么解決(醫(yī)保卡黑名單如何補救)
- []信用卡第一次還款日期怎么算的(信用卡還款日怎么算年限)
- []全球熱資訊!用京醫(yī)通掛號醫(yī)保卡還能報銷嗎(京醫(yī)通綁定社保卡能不能報銷住院)
- []全球頭條:多少人的信用卡額度達(dá)到30萬以上(多少人的信用卡額度達(dá)到30萬)
- []全球百事通!新地NOVO LAND 2B期最快下星期上載樓書
- []觀察:石嘴山新型冠狀病毒肺炎疫情:2月8日石嘴山疫情最新消息今天數(shù)據(jù)統(tǒng)計情況通報
- []環(huán)球熱文:雙杰電氣: “東數(shù)西算”工程是國家重點發(fā)展戰(zhàn)略之一,也會用到12kV的配電設(shè)備
- []百盛商業(yè)確認(rèn)租賃四川綿陽科技城新區(qū)物業(yè) 用作經(jīng)營購物中心等
- []需要進(jìn)一步核實及完善 海航投資延期回復(fù)深交所關(guān)注函
- []新湖中寶:控股股東之一致行動人900萬股解除質(zhì)押
- []世界熱消息:中國銀河:公司堅持服務(wù)國家戰(zhàn)略、服務(wù)中小微企業(yè)與提高業(yè)務(wù)核心競爭力相結(jié)合
- []【環(huán)球快播報】博世科:(1)公司暫無微生物燃料電池相關(guān)領(lǐng)域的規(guī)劃
- []奮達(dá)科技:公司與首航簽署了戰(zhàn)略合作協(xié)議,具體請參考以往公告
- []天天快報!多晶硅價格上漲!
- []全球最資訊丨數(shù)字信號處理技術(shù)論文
- []四連漲!硅料最高價至249元/kg
- []環(huán)球視訊!海量項目信息!光伏行業(yè)最新報告出爐
- []當(dāng)前熱訊:再下一城!越秀以33.12億+現(xiàn)房銷售4.5萬平競得昌平信息園二期地塊
- []新動態(tài):西方制裁打擊俄羅斯石油收入的背后:巨額利潤究竟流向了哪?
- []全球焦點!2月8日豪鵬科技漲停分析:鋰電池,動力電池回收,新能源汽車概念熱股
- []環(huán)球時訊:建發(fā)股份申請發(fā)行不超過45億元公司債 獲發(fā)改委同意注冊
- []2月8日真視通漲停分析:應(yīng)急產(chǎn)業(yè),東數(shù)西算,軍民融合概念熱股
- []世界快報:溫州城建30億私募債項目狀態(tài)更新為“已受理”
- []短訊!哈藥股份:道圣康膜不是本公司生產(chǎn)的產(chǎn)品,黑龍江大眾安泰藥業(yè)有限公司不是本公司的下屬企業(yè)
- []湖州安吉6宗地均以底價成交 兩山國有控股6.58億連拿2宗
- []“老撕雞防騙”掛羊頭賣狗肉,誤導(dǎo)投資客戶,30億客戶資金打水漂
- []2月8日新綸新材漲停分析:固態(tài)電池,鋰電池,寧德時代概念股概念熱股
- []全球熱頭條丨2月8日鴻博股份漲停分析:包裝印刷,小家電,體育產(chǎn)業(yè)概念熱股
- []天天微動態(tài)丨中原:一手私樓開放式及一房貨尾量比例共占逾三成
- []如何簡單的自制黑椒牛排?自制黑椒牛排的方法步驟?
- []騰訊開心鼠英語是騰訊旗下嗎?騰訊開心鼠英語介紹
- []天天要聞:左立熊小玥還在一起嗎?左立個人資料介紹?
- []環(huán)球播報:博大考神職稱計算機(jī)軟件破解版,博大考神職稱計算機(jī)考試
- []當(dāng)前頭條:詩曼芬是幾線品牌?詩曼芬品牌資料介紹?
- []綿陽美食有哪些?綿陽美食分享?
- []世界即時看!網(wǎng)易smtp的25端口可以使用ssl端口?操作步驟
- []世界看點:深圳楊梅坑在哪里?楊梅坑好不好玩?
- 環(huán)球熱訊:優(yōu)秀的企業(yè)績效考核系統(tǒng)——MVC設(shè)計模式
- 熱資訊!濕簾冷風(fēng)機(jī)原理是什么?濕簾冷風(fēng)機(jī)的作用與工作原理
- sqoop導(dǎo)入pg11常見問題及解決方法
- 世界熱訊:onekeyghost安裝器一鍵還原重裝電腦系統(tǒng)
- 兩臺未聯(lián)網(wǎng)的Win7電腦怎么建立局域網(wǎng)游戲?操作步驟
- 無線路由器怎么設(shè)置?TP-LINK無線路由器設(shè)置教程
- 【環(huán)球聚看點】組件化元數(shù)據(jù)結(jié)構(gòu)設(shè)計——PageMaker
- 播報:前端安全 跨站腳本攻擊是一種代碼注入攻擊
- 熱門:如何登錄新浪微博html5?新浪微博怎么登陸?
- 環(huán)球即時看!華為鴻蒙系統(tǒng)怎么安裝第三方軟件?安裝方法步驟
- B站注冊資本增幅400%至5億 目前由陳睿全資持股
- 光源資本出任獨家財務(wù)顧問 沐曦集成電路10億元A輪融資宣告完成
- 巨輪智能2021年上半年營收11.24億元 期內(nèi)研發(fā)費用投入增長19.05%
- 紅棗期貨尾盤拉升大漲近6% 目前紅棗市場總庫存約30萬噸
- 嘉銀金科發(fā)布2021年Q2財報 期內(nèi)凈利潤達(dá)1.27億元同比增長208%
- 成都銀行2021上半年凈利33.89億元 期內(nèi)實現(xiàn)營收同比增長17.27億元
- 汽車之家發(fā)布2021年第二季度業(yè)績 期內(nèi)新能源汽車品牌收入增長238%
- 中信銀行上半年實現(xiàn)凈利潤290.31億元 期末不良貸款余額706.82億元
- 光伏概念掀起漲停潮交易價格創(chuàng)新高 全天成交額達(dá)1.29億元
- 上半年生物藥大增45% 關(guān)鍵財務(wù)指標(biāo)好轉(zhuǎn)營收賬款持續(xù)下降
- 環(huán)球即時:elasticsearch怎么安裝插件?elasticsearch拼音分詞插件安裝教程
- 資訊推薦:周杰倫演武神的一部電影叫什么名字?講述了什么劇情?
- 從虛擬化安全到容器安全:Docker容器的安全機(jī)制與解決方案
- 快報:陋室銘作者是誰?陋室銘作者資料介紹?
- 天天精選!mysql設(shè)計總結(jié) 基于mysql的bbs設(shè)計總結(jié)
- 含有狗的諺語有哪些?含有狗的諺語匯總?
- 駱駝精神是什么樣的精神?駱駝精神介紹?
- 全球熱門:12306搶票網(wǎng)站靠譜嗎?火車票候補購票概率有多大?
- 天天新動態(tài):什么貸款能貸10年以上(有什么貸款能貸五年)
- 全球今頭條!攜程:年后跨境航班“量升價跌”,海外酒店錯峰均價降一成
- 每日關(guān)注!艾莉森洛曼為什么不火?瑤瑤來為您解答
- 環(huán)球動態(tài):貨拉拉推出同城門到門跑腿服務(wù) 預(yù)計4月正式開放服務(wù)和騎手接單
- 上海浦東香楠路城市經(jīng)典會所二次拍賣流拍 當(dāng)前價1.08億元
- 每日短訊:香港“高才通計劃”接獲7417宗申請 其中5799宗獲批
- 焦點觀察:c盤臨時文件可以清理嗎?c盤臨時文件可以刪除
- 【全球新要聞】衛(wèi)生整頓工作總結(jié)(通用31篇)
- 豫能控股:公司指定的信息披露媒體有《證券時報》《上海證券報》和巨潮資訊網(wǎng),相關(guān)費用以合同簽訂為準(zhǔn)
- 多普達(dá)830怎么樣?多普達(dá)830手機(jī)報價及性能配置介紹
- visit怎么讀的?will和visit讀音相同嗎?
- 全球滾動:《從結(jié)婚開始戀愛》什么時候播出?從結(jié)婚開始戀愛演員表
- 當(dāng)前簡訊:福州高新投資1.09億元摘閩侯一宗宅地 將建設(shè)拆遷安置房項目
- 快看點丨華為y320怎么樣?華為y320報價及簡評分享
- 今日熱聞!西安空調(diào)移機(jī)哪家好?西安空調(diào)移機(jī)廠家技術(shù)信得過
- 焦點精選!win10怎么徹底清除win32trojan病毒?win32 trojan病毒清除教程
- 全球看點:尼康鏡頭標(biāo)識的含義是什么?詳情介紹
- 江河集團(tuán):公司在海外的業(yè)務(wù)主要集中在東南亞地區(qū),暫無在中東地區(qū)開展業(yè)務(wù)的計劃
- 全球最資訊丨春秋航空啟動大規(guī)模線下招聘
- 熱點在線丨【linux系統(tǒng)命令大全】免費使用和自由傳播的Unix系統(tǒng)
- matlab軟件實驗原理 matlab中的圖像增強與復(fù)原實驗
- 社保基數(shù)忘記申報,基數(shù)自動上調(diào)了怎么回事(公積金基數(shù)上調(diào)了社保基數(shù)沒調(diào))
- 環(huán)球今日報丨皇家加勒比:2022年Q4營收26億美元,凈虧損5億美元
- 世界觀焦點:java代碼實現(xiàn)二分法查找 二分法的實現(xiàn)
- 世界關(guān)注:北京社保外埠農(nóng)村勞動力(社保為外埠農(nóng)村勞動力是什么意思)
- 【環(huán)球新要聞】Waze將很快獲得Android Auto最酷的新功能之一
- 最新消息:狄拉克:量子場論的研究方法
- 環(huán)球速讀:10套極好用的PS繪畫筆刷工具 簡直就是神器
- 環(huán)球關(guān)注:越秀地產(chǎn)以25.99億競得石景山蘋果園地塊 配建1.5萬平方米現(xiàn)房
- 世界短訊!京山輕機(jī):如公司與其他公司發(fā)生達(dá)到信息披露標(biāo)準(zhǔn)的重大合作項目,公司將按規(guī)定及時履行信息披露義務(wù)
- 快訊:拉薩城建投資30億元私募債項目狀態(tài)更新為“已反饋”
- 全球快資訊:丹化科技:公司目前沒有這方面的計劃
- 全球熱訊:房企融資分化:有國企兩月授信超千億,出險企業(yè)盼借新還舊應(yīng)對償債高峰
- 華聯(lián)控股:華聯(lián)南山A區(qū)更新項目有關(guān)申請報批工作在推進(jìn)中
- 當(dāng)前關(guān)注:深圳安托山新業(yè)花園動工 將提供226套保障性住房
- 環(huán)球熱點評!*ST日海:上述資產(chǎn)轉(zhuǎn)讓的會計影響會體現(xiàn)在2022年年度報告中
- 信息:抖音在杭州成立無限能量房產(chǎn)經(jīng)紀(jì)公司 注冊資本150萬
- 當(dāng)前視訊!支付寶免費保單啥意思(支付寶免費領(lǐng)保單可以領(lǐng)嗎)
- 徽商銀行怎么交個人社保(我的社保是在安徽合肥徽商銀行交的,怎樣轉(zhuǎn)到天津社保交費)
- 【全球報資訊】“19泰達(dá)01”回售數(shù)量234.49萬手 回售金額23.45億元
- 環(huán)球快資訊:新華制藥:公司是全球主要解熱鎮(zhèn)痛等類藥物供應(yīng)商,與眾多制劑生產(chǎn)企業(yè)均有業(yè)務(wù)往來
- 最新資訊:住建部等:啟動公共領(lǐng)域車輛全面電動化先行區(qū)試點
- 美的置業(yè)10.2億元公司債將于2月13日提前摘牌 利率4.4%
- 商湯-W跌超4% 此前遭軟銀集團(tuán)減持近3億股
- 世界聚焦:江西:落實16條金融措施 有效防范化解優(yōu)質(zhì)頭部房企風(fēng)險
- 全球今頭條!聲迅股份:公司高度關(guān)注ChatGPT相關(guān)的行業(yè)化應(yīng)用,也在探索ChatGPT與公司業(yè)務(wù)的結(jié)合點
- 動態(tài):全城高考的觀后感
- 精彩看點:海得控制:公司在系統(tǒng)解決方案業(yè)務(wù)中會涉及百度相關(guān)技術(shù)與產(chǎn)品的應(yīng)用
- 咨詢公司報告:中國旅游業(yè)復(fù)蘇路徑評估
- 超過退休年齡可以補交養(yǎng)老金嗎(超過退休年齡可以補交養(yǎng)老金嗎?)
- 【全球播資訊】降低存量房貸利率,可行嗎?
- 世界最資訊丨金科地產(chǎn):累計完成 285.77 億元有息負(fù)債的展期工作
- 廣東發(fā)改委:推動國家出臺金融支持橫琴粵澳深度合作區(qū)建設(shè)政策
- 最資訊丨首進(jìn)北京!中建東孚14.26億元競得北京朝陽區(qū)小紅門地塊
- 環(huán)球快報:廣東省發(fā)改委:力爭橫琴粵澳深度合作區(qū)年內(nèi)“封關(guān)運作”
- 【全球獨家】實益達(dá):公司暫無chatgpt相關(guān)技術(shù)。關(guān)于公司具體業(yè)務(wù)內(nèi)容詳見公司披露的定期報告
- 【BT金融分析師】豐田重心偏向混動車型,分析師稱其沒全部押注電動汽車
- 前沿?zé)狳c:華夏銀行信用卡賬單日和還款日(華夏銀行信用卡賬單日和還款日)
- 【世界播資訊】萬達(dá)商管成功發(fā)行3億美元債,消息稱有望二季度重返港股
- 環(huán)球觀天下!越秀以25.99億元+1.5萬平現(xiàn)房銷售面積競得北京石景山1宗地塊
- 環(huán)球快資訊:奧普光電:公司主營業(yè)務(wù)為光電測控儀器設(shè)備、光學(xué)材料和光柵編碼器等產(chǎn)品的研發(fā)、生產(chǎn)和銷售
- 中泰證券:強預(yù)期與弱現(xiàn)實的博弈 關(guān)注低PB房企及央企地產(chǎn)附屬物業(yè)公司
- 【全球速看料】富力地產(chǎn)欠稅金額超千萬
- 當(dāng)前快訊:江陰銀行:財務(wù)總監(jiān)親屬因誤操作導(dǎo)致買賣公司股票構(gòu)成短線交易
- 深南電路:公司在保障正常生產(chǎn)經(jīng)營和項目建設(shè)資金需要的同時,持續(xù)加強資金的統(tǒng)籌管理,實現(xiàn)資金的高效利用
- 銀河證券:房地產(chǎn)基本面仍在筑底 集中供地規(guī)則優(yōu)化
- 環(huán)球微頭條丨生源地助學(xué)貸款可以異地辦理嗎(生源地助學(xué)貸款可以異地辦理嗎)
- 爆冷!亞冠冠軍3-2淘汰南美冠軍進(jìn)世俱杯決賽 或與皇馬爭冠
- 天天頭條:英大人壽內(nèi)勤怎么樣(英大人壽內(nèi)勤好不好干)
- 如何訓(xùn)練抗干擾能力?訓(xùn)練抗干擾能力的方法步驟?
- 每日快播:狼和小羊的作者是誰?狼和小羊是出自哪里?
- 天天時訊:《橫琴粵澳深度合作區(qū)發(fā)展促進(jìn)條例》公布 自3月1日起施行
- 【東海期貨2月8日產(chǎn)業(yè)鏈日報】能化篇:中國需求信心增強,油價大幅上漲
- 天天熱頭條丨潤華生活服務(wù)全球發(fā)售的穩(wěn)定價格期于2月8日結(jié)束
- 頭條焦點:hm是什么牌子的衣服?HM是什么的簡稱?
- 環(huán)球滾動:國信期貨早評:原油高漲,國際油脂震蕩走高,原糖走升
- 每日熱訊!羥脯氨酸怎么測定?羥脯氨酸的測定方法?
- 快播:中信建投期貨2月8日早間交易策略
- 華光環(huán)能:預(yù)計占推廣項目收入的比例不到5%,相關(guān)涉及信息屬于商業(yè)性保密信息,不便于披露
- 帶一毛字的成語有多少?帶一毛字的成語匯總?
- 【獨家焦點】什么叫甲基化?甲基化是指什么?
- 世界看熱訊:傳無錫首房首貸利率將降至3.8%!
- 頭條:富貴竹怎么養(yǎng)殖?富貴竹的養(yǎng)殖方法是什么?
- 血紅蛋白正常值是多少_血紅
- 當(dāng)前速訊:xwd四輪驅(qū)動是什么?xwd四輪驅(qū)動配置怎么樣?
- 天天亮點!中國新城鎮(zhèn)領(lǐng)漲港股內(nèi)房股 A股地產(chǎn)板塊早盤走強
- 天天即時看!北京漲價業(yè)主越來越多
- 【世界速看料】春日宴主演都有誰?春日宴講述了什么故事?
- 環(huán)球觀點:中交地產(chǎn):截止1月20日收盤的股東人數(shù)為68029
- 全球滾動:云南省的簡稱是什么?云南省的面積有多大?
- 焦點熱議:【東海期貨2月8日產(chǎn)業(yè)鏈日報】貴金屬篇:鮑威爾發(fā)言偏鷹,金銀震蕩